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

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

Issue 8477005: Add policies to specify an enterprise web store. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add tests for ComponentLoader. Created 9 years, 1 month 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) 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/component_loader.h" 5 #include "chrome/browser/extensions/component_loader.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/path_service.h" 8 #include "base/path_service.h"
9 #include "base/json/json_value_serializer.h" 9 #include "base/json/json_value_serializer.h"
10 #include "chrome/browser/browser_process.h" 10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/prefs/pref_change_registrar.h"
13 #include "chrome/browser/prefs/pref_notifier.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/chrome_notification_types.h"
12 #include "chrome/common/chrome_paths.h" 16 #include "chrome/common/chrome_paths.h"
13 #include "chrome/common/chrome_switches.h" 17 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/extensions/extension.h" 18 #include "chrome/common/extensions/extension.h"
15 #include "chrome/common/pref_names.h" 19 #include "chrome/common/pref_names.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h"
16 #include "grit/browser_resources.h" 22 #include "grit/browser_resources.h"
17 #include "ui/base/resource/resource_bundle.h" 23 #include "ui/base/resource/resource_bundle.h"
18 24
19 #if defined(OFFICIAL_BUILD) 25 #if defined(OFFICIAL_BUILD)
20 #include "chrome/browser/defaults.h" 26 #include "chrome/browser/defaults.h"
21 #endif 27 #endif
22 28
23 namespace {
24
25 typedef std::list<std::pair<FilePath::StringType, int> >
26 ComponentExtensionList;
27
28 #if defined(FILE_MANAGER_EXTENSION)
29 void AddFileManagerExtension(ComponentExtensionList* component_extensions) {
30 #ifndef NDEBUG
31 const CommandLine* command_line = CommandLine::ForCurrentProcess();
32 if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
33 FilePath filemgr_extension_path =
34 command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath);
35 component_extensions->push_back(std::make_pair(
36 filemgr_extension_path.value(),
37 IDR_FILEMANAGER_MANIFEST));
38 return;
39 }
40 #endif // NDEBUG
41 component_extensions->push_back(std::make_pair(
42 FILE_PATH_LITERAL("file_manager"),
43 IDR_FILEMANAGER_MANIFEST));
44 }
45 #endif // defined(FILE_MANAGER_EXTENSION)
46
47 } // namespace
48
49 namespace extensions { 29 namespace extensions {
50 30
51 bool ComponentLoader::ComponentExtensionInfo::Equals( 31 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
52 const ComponentExtensionInfo& other) const { 32 PrefService* prefs)
53 return other.manifest == manifest && other.root_directory == root_directory; 33 : prefs_(prefs), extension_service_(extension_service) {
54 } 34 pref_change_registrar_.Init(prefs);
55 35
56 ComponentLoader::ComponentLoader(ExtensionService* extension_service) 36 // This pref is set by policy. We have to watch it for change because on
57 : extension_service_(extension_service) { 37 // ChromeOS, policy isn't loaded until after the browser process is started.
38 pref_change_registrar_.Add(prefs::kEnterpriseWebStoreURL, this);
58 } 39 }
59 40
60 ComponentLoader::~ComponentLoader() { 41 ComponentLoader::~ComponentLoader() {
61 } 42 }
62 43
63 void ComponentLoader::LoadAll() { 44 void ComponentLoader::LoadAll() {
64 for (RegisteredComponentExtensions::iterator it = 45 for (RegisteredComponentExtensions::iterator it =
65 component_extensions_.begin(); 46 component_extensions_.begin();
66 it != component_extensions_.end(); ++it) { 47 it != component_extensions_.end(); ++it) {
67 Load(*it); 48 Load(*it);
68 } 49 }
69 } 50 }
70 51
52 DictionaryValue* ComponentLoader::ParseManifest(
53 const std::string& manifest_contents) const {
54 JSONStringValueSerializer serializer(manifest_contents);
55 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
56
57 if (!manifest.get() || !manifest->IsType(Value::TYPE_DICTIONARY)) {
58 LOG(ERROR) << "Failed to parse extension manifest.";
59 return NULL;
60 }
61 // Transfer ownership to the caller.
62 return static_cast<DictionaryValue*>(manifest.release());
63 }
64
71 const Extension* ComponentLoader::Add( 65 const Extension* ComponentLoader::Add(
72 const std::string& manifest, const FilePath& root_directory) { 66 int manifest_resource_id,
73 ComponentExtensionInfo info(manifest, root_directory); 67 const FilePath& root_directory) {
74 Register(info); 68 std::string manifest_contents =
69 ResourceBundle::GetSharedInstance().GetRawDataResource(
70 manifest_resource_id).as_string();
71 return Add(manifest_contents, root_directory);
72 }
73
74 const Extension* ComponentLoader::Add(
75 std::string& manifest_contents,
76 const FilePath& root_directory) {
77 // The Value is kept for the lifetime of the ComponentLoader. This is
78 // required in case LoadAll() is called again.
79 DictionaryValue* manifest = ParseManifest(manifest_contents);
80 if (manifest)
81 return Add(manifest, root_directory);
82 return NULL;
83 }
84
85 const Extension* ComponentLoader::Add(
86 const DictionaryValue* parsed_manifest,
87 const FilePath& root_directory) {
88 // Get the absolute path to the extension.
89 FilePath absolute_path(root_directory);
90 if (!absolute_path.IsAbsolute()) {
91 if (PathService::Get(chrome::DIR_RESOURCES, &absolute_path)) {
92 absolute_path = absolute_path.Append(root_directory);
93 } else {
94 NOTREACHED();
95 }
96 }
97
98 ComponentExtensionInfo info(parsed_manifest, absolute_path);
99 component_extensions_.push_back(info);
75 if (extension_service_->is_ready()) 100 if (extension_service_->is_ready())
76 return Load(info); 101 return Load(info);
77 return NULL; 102 return NULL;
78 } 103 }
79 104
80 const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) { 105 const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) {
81 JSONStringValueSerializer serializer(info.manifest);
82 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
83 if (!manifest.get()) {
84 LOG(ERROR) << "Failed to parse manifest for extension";
85 return NULL;
86 }
87
88 int flags = Extension::REQUIRE_KEY; 106 int flags = Extension::REQUIRE_KEY;
89 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT)) 107 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
90 flags |= Extension::STRICT_ERROR_CHECKS; 108 flags |= Extension::STRICT_ERROR_CHECKS;
91 std::string error; 109 std::string error;
92 scoped_refptr<const Extension> extension(Extension::Create( 110 scoped_refptr<const Extension> extension(Extension::Create(
93 info.root_directory, 111 info.root_directory,
94 Extension::COMPONENT, 112 Extension::COMPONENT,
95 *static_cast<DictionaryValue*>(manifest.get()), 113 *info.manifest,
96 flags, 114 flags,
97 &error)); 115 &error));
98 if (!extension.get()) { 116 if (!extension.get()) {
99 LOG(ERROR) << error; 117 LOG(ERROR) << error;
100 return NULL; 118 return NULL;
101 } 119 }
102 extension_service_->AddExtension(extension); 120 extension_service_->AddExtension(extension);
103 return extension; 121 return extension;
104 } 122 }
105 123
106 void ComponentLoader::Remove(const std::string& manifest_str) { 124 void ComponentLoader::Remove(const FilePath& root_directory) {
107 // Unload the extension. 125 // Find the ComponentExtensionInfo for the extension.
108 JSONStringValueSerializer serializer(manifest_str); 126 RegisteredComponentExtensions::iterator it = component_extensions_.begin();
109 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); 127 for (; it != component_extensions_.end(); ++it) {
110 if (!manifest.get()) { 128 if (it->root_directory == root_directory)
111 LOG(ERROR) << "Failed to parse manifest for extension"; 129 break;
130 }
131 // If the extension is not in the list, there's nothing to do.
132 if (it == component_extensions_.end())
112 return; 133 return;
113 } 134
135 const DictionaryValue* manifest = it->manifest;
136
137 // Remove the extension from the list of registered extensions.
138 *it = component_extensions_.back();
139 component_extensions_.pop_back();
140
141 // Determine the extension id and unload the extension.
114 std::string public_key; 142 std::string public_key;
115 std::string public_key_bytes; 143 std::string public_key_bytes;
116 std::string id; 144 std::string id;
117 if (!static_cast<DictionaryValue*>(manifest.get())-> 145 if (!manifest->GetString(
118 GetString(extension_manifest_keys::kPublicKey, &public_key) || 146 extension_manifest_keys::kPublicKey, &public_key) ||
119 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) || 147 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) ||
120 !Extension::GenerateId(public_key_bytes, &id)) { 148 !Extension::GenerateId(public_key_bytes, &id)) {
121 LOG(ERROR) << "Failed to get extension id"; 149 LOG(ERROR) << "Failed to get extension id";
122 return; 150 return;
123 } 151 }
124 extension_service_-> 152 extension_service_->
125 UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE); 153 UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE);
126
127 // Unregister the extension.
128 RegisteredComponentExtensions new_component_extensions;
129 for (RegisteredComponentExtensions::iterator it =
130 component_extensions_.begin();
131 it != component_extensions_.end(); ++it) {
132 if (it->manifest != manifest_str)
133 new_component_extensions.push_back(*it);
134 }
135 component_extensions_.swap(new_component_extensions);
136 } 154 }
137 155
138 // We take ComponentExtensionList: 156 void ComponentLoader::AddFileManagerExtension() {
139 // path, manifest ID => full manifest, absolute path 157 #if defined(FILE_MANAGER_EXTENSION)
158 #ifndef NDEBUG
159 const CommandLine* command_line = CommandLine::ForCurrentProcess();
160 if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
161 FilePath filemgr_extension_path(
162 command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath));
163 Add(IDR_FILEMANAGER_MANIFEST, filemgr_extension_path);
164 return;
165 }
166 #endif // NDEBUG
167 Add(IDR_FILEMANAGER_MANIFEST, FilePath("file_manager"));
168 #endif // defined(FILE_MANAGER_EXTENSION)
169 }
170
171 void ComponentLoader::AddOrReloadEnterpriseWebStore() {
172 FilePath path("enterprise_web_store");
173
174 // Remove the extension if it was already loaded.
175 Remove(path);
176
177 std::string enterprise_webstore_url =
178 prefs_->GetString(prefs::kEnterpriseWebStoreURL);
179
180 // Load the extension only if the URL preference is set.
181 if (!enterprise_webstore_url.empty()) {
182 std::string manifest_contents =
183 ResourceBundle::GetSharedInstance().GetRawDataResource(
184 IDR_ENTERPRISE_WEBSTORE_MANIFEST).as_string();
185
186 // The manifest is missing some values that are provided by policy.
187 DictionaryValue* manifest = ParseManifest(manifest_contents);
188 if (manifest) {
189 std::string name = prefs_->GetString(prefs::kEnterpriseWebStoreName);
190 manifest->SetString("app.launch.web_url", enterprise_webstore_url);
191 manifest->SetString("name", name);
192 Add(manifest, path);
193 }
194 }
195 }
196
140 void ComponentLoader::AddDefaultComponentExtensions() { 197 void ComponentLoader::AddDefaultComponentExtensions() {
141 ComponentExtensionList component_extensions; 198 Add(IDR_BOOKMARKS_MANIFEST, FilePath("bookmark_manager"));
142
143 // Bookmark manager.
144 component_extensions.push_back(std::make_pair(
145 FILE_PATH_LITERAL("bookmark_manager"),
146 IDR_BOOKMARKS_MANIFEST));
147 199
148 #if defined(FILE_MANAGER_EXTENSION) 200 #if defined(FILE_MANAGER_EXTENSION)
149 AddFileManagerExtension(&component_extensions); 201 AddFileManagerExtension();
150 #endif 202 #endif
151 203
152 #if defined(TOUCH_UI) 204 #if defined(TOUCH_UI)
153 component_extensions.push_back(std::make_pair( 205 Add(IDR_KEYBOARD_MANIFEST, FilePath("keyboard"));
154 FILE_PATH_LITERAL("keyboard"),
155 IDR_KEYBOARD_MANIFEST));
156 #endif 206 #endif
157 207
158 #if defined(OS_CHROMEOS) 208 #if defined(OS_CHROMEOS)
159 component_extensions.push_back(std::make_pair( 209 Add(IDR_MOBILE_MANIFEST,
160 FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"), 210 FilePath("/usr/share/chromeos-assets/mobile"));
161 IDR_MOBILE_MANIFEST));
162 211
163 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 212 const CommandLine* command_line = CommandLine::ForCurrentProcess();
164 if (command_line->HasSwitch(switches::kAuthExtensionPath)) { 213 if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
165 FilePath auth_extension_path = 214 FilePath auth_extension_path =
166 command_line->GetSwitchValuePath(switches::kAuthExtensionPath); 215 command_line->GetSwitchValuePath(switches::kAuthExtensionPath);
167 component_extensions.push_back(std::make_pair( 216 Add(IDR_GAIA_TEST_AUTH_MANIFEST, auth_extension_path);
168 auth_extension_path.value(),
169 IDR_GAIA_TEST_AUTH_MANIFEST));
170 } else { 217 } else {
171 component_extensions.push_back(std::make_pair( 218 Add(IDR_GAIA_AUTH_MANIFEST,
172 FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"), 219 FilePath("/usr/share/chromeos-assets/gaia_auth"));
173 IDR_GAIA_AUTH_MANIFEST));
174 } 220 }
175 221
176 #if defined(OFFICIAL_BUILD) 222 #if defined(OFFICIAL_BUILD)
177 if (browser_defaults::enable_help_app) { 223 if (browser_defaults::enable_help_app) {
178 component_extensions.push_back(std::make_pair( 224 Add(IDR_HELP_MANIFEST,
179 FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"), 225 FilePath("/usr/share/chromeos-assets/helpapp"));
180 IDR_HELP_MANIFEST));
181 } 226 }
182 #endif 227 #endif
183 #endif 228 #endif // !defined(OS_CHROMEOS)
184 229
185 // Web Store. 230 Add(IDR_WEBSTORE_MANIFEST, FilePath("web_store"));
186 component_extensions.push_back(std::make_pair(
187 FILE_PATH_LITERAL("web_store"),
188 IDR_WEBSTORE_MANIFEST));
189 231
190 #if !defined(OS_CHROMEOS) 232 #if !defined(OS_CHROMEOS)
191 // Cloud Print component app. Not required on Chrome OS. 233 // Cloud Print component app. Not required on Chrome OS.
192 component_extensions.push_back(std::make_pair( 234 Add(IDR_CLOUDPRINT_MANIFEST, FilePath("cloud_print"));
193 FILE_PATH_LITERAL("cloud_print"), 235 #endif
194 IDR_CLOUDPRINT_MANIFEST));
195 #endif // !defined(OS_CHROMEOS)
196
197 for (ComponentExtensionList::iterator iter = component_extensions.begin();
198 iter != component_extensions.end(); ++iter) {
199 FilePath path(iter->first);
200 if (!path.IsAbsolute()) {
201 if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
202 path = path.Append(iter->first);
203 } else {
204 NOTREACHED();
205 }
206 }
207
208 std::string manifest =
209 ResourceBundle::GetSharedInstance().GetRawDataResource(
210 iter->second).as_string();
211 Add(manifest, path);
212 }
213 236
214 #if defined(OS_CHROMEOS) 237 #if defined(OS_CHROMEOS)
215 // Register access extensions only if accessibility is enabled. 238 // Register access extensions only if accessibility is enabled.
216 if (g_browser_process->local_state()-> 239 if (g_browser_process->local_state()->
217 GetBoolean(prefs::kAccessibilityEnabled)) { 240 GetBoolean(prefs::kAccessibilityEnabled)) {
218 FilePath path = FilePath(extension_misc::kAccessExtensionPath) 241 FilePath path = FilePath(extension_misc::kAccessExtensionPath)
219 .AppendASCII(extension_misc::kChromeVoxDirectoryName); 242 .AppendASCII(extension_misc::kChromeVoxDirectoryName);
220 std::string manifest = 243 Add(IDR_CHROMEVOX_MANIFEST, path);
221 ResourceBundle::GetSharedInstance().GetRawDataResource(
222 IDR_CHROMEVOX_MANIFEST).as_string();
223 Add(manifest, path);
224 } 244 }
225 #endif 245 #endif
246
247 // If a URL for the enterprise webstore has been specified, load the
248 // component extension. This extension might also be loaded later, because
249 // it is specified by policy, and on ChromeOS policies are loaded after
250 // the browser process has started.
251 AddOrReloadEnterpriseWebStore();
252 }
253
254 void ComponentLoader::Observe(
255 int type,
256 const content::NotificationSource& source,
257 const content::NotificationDetails& details) {
258 if (type == chrome::NOTIFICATION_PREF_CHANGED) {
259 const std::string* name =
260 content::Details<const std::string>(details).ptr();
261 if (*name == prefs::kEnterpriseWebStoreURL)
262 AddOrReloadEnterpriseWebStore();
263 else
264 NOTREACHED();
265 } else {
266 NOTREACHED();
267 }
268 }
269
270 // static
271 void ComponentLoader::RegisterUserPrefs(PrefService* prefs) {
272 prefs->RegisterStringPref(prefs::kEnterpriseWebStoreURL,
273 std::string() /* default_value */,
274 PrefService::UNSYNCABLE_PREF);
275 prefs->RegisterStringPref(prefs::kEnterpriseWebStoreName,
276 std::string() /* default_value */,
277 PrefService::UNSYNCABLE_PREF);
226 } 278 }
227 279
228 } // namespace extensions 280 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698