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

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

Issue 10692168: Moved ExternalExtensionLoaders/Providers into extensions namespace (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 5 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/external_extension_provider_impl.h"
6
7 #include "base/command_line.h"
8 #include "base/file_path.h"
9 #include "base/logging.h"
10 #include "base/memory/linked_ptr.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/path_service.h"
13 #include "base/string_util.h"
14 #include "base/values.h"
15 #include "base/version.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/external_extension_provider_interface.h"
19 #include "chrome/browser/extensions/external_policy_extension_loader.h"
20 #include "chrome/browser/extensions/external_pref_extension_loader.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "ui/base/l10n/l10n_util.h"
27
28 #if defined(OS_CHROMEOS)
29 #include "chrome/browser/chromeos/login/user_manager.h"
30 #include "chrome/browser/policy/app_pack_updater.h"
31 #include "chrome/browser/policy/browser_policy_connector.h"
32 #endif
33
34 #if !defined(OS_CHROMEOS)
35 #include "chrome/browser/extensions/default_apps.h"
36 #endif
37
38 #if defined(OS_WIN)
39 #include "chrome/browser/extensions/external_registry_extension_loader_win.h"
40 #endif
41
42 using content::BrowserThread;
43 using extensions::Extension;
44
45 // Constants for keeping track of extension preferences in a dictionary.
46 const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx";
47 const char ExternalExtensionProviderImpl::kExternalVersion[] =
48 "external_version";
49 const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] =
50 "external_update_url";
51 const char ExternalExtensionProviderImpl::kSupportedLocales[] =
52 "supported_locales";
53 const char ExternalExtensionProviderImpl::kIsBookmarkApp[] =
54 "is_bookmark_app";
55
56 ExternalExtensionProviderImpl::ExternalExtensionProviderImpl(
57 VisitorInterface* service,
58 ExternalExtensionLoader* loader,
59 Extension::Location crx_location,
60 Extension::Location download_location,
61 int creation_flags)
62 : crx_location_(crx_location),
63 download_location_(download_location),
64 service_(service),
65 prefs_(NULL),
66 ready_(false),
67 loader_(loader),
68 creation_flags_(creation_flags),
69 auto_acknowledge_(false) {
70 loader_->Init(this);
71 }
72
73 ExternalExtensionProviderImpl::~ExternalExtensionProviderImpl() {
74 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
75 loader_->OwnerShutdown();
76 }
77
78 void ExternalExtensionProviderImpl::VisitRegisteredExtension() {
79 // The loader will call back to SetPrefs.
80 loader_->StartLoading();
81 }
82
83 void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) {
84 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
85
86 // Check if the service is still alive. It is possible that it went
87 // away while |loader_| was working on the FILE thread.
88 if (!service_) return;
89
90 prefs_.reset(prefs);
91 ready_ = true; // Queries for extensions are allowed from this point.
92
93 // Set of unsupported extensions that need to be deleted from prefs_.
94 std::set<std::string> unsupported_extensions;
95
96 // Notify ExtensionService about all the extensions this provider has.
97 for (DictionaryValue::key_iterator i = prefs_->begin_keys();
98 i != prefs_->end_keys(); ++i) {
99 const std::string& extension_id = *i;
100 DictionaryValue* extension;
101
102 if (!Extension::IdIsValid(extension_id)) {
103 LOG(WARNING) << "Malformed extension dictionary: key "
104 << extension_id.c_str() << " is not a valid id.";
105 continue;
106 }
107
108 if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) {
109 LOG(WARNING) << "Malformed extension dictionary: key "
110 << extension_id.c_str()
111 << " has a value that is not a dictionary.";
112 continue;
113 }
114
115 FilePath::StringType external_crx;
116 Value* external_version_value;
117 std::string external_version;
118 std::string external_update_url;
119
120 bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
121
122 bool has_external_version = false;
123 if (extension->Get(kExternalVersion, &external_version_value)) {
124 if (external_version_value->IsType(Value::TYPE_STRING)) {
125 external_version_value->GetAsString(&external_version);
126 has_external_version = true;
127 } else {
128 LOG(WARNING) << "Malformed extension dictionary for extension: "
129 << extension_id.c_str() << ". " << kExternalVersion
130 << " value must be a string.";
131 continue;
132 }
133 }
134
135 bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
136 &external_update_url);
137 if (has_external_crx != has_external_version) {
138 LOG(WARNING) << "Malformed extension dictionary for extension: "
139 << extension_id.c_str() << ". " << kExternalCrx
140 << " and " << kExternalVersion << " must be used together.";
141 continue;
142 }
143
144 if (has_external_crx == has_external_update_url) {
145 LOG(WARNING) << "Malformed extension dictionary for extension: "
146 << extension_id.c_str() << ". Exactly one of the "
147 << "followng keys should be used: " << kExternalCrx
148 << ", " << kExternalUpdateUrl << ".";
149 continue;
150 }
151
152 // Check that extension supports current browser locale.
153 ListValue* supported_locales = NULL;
154 if (extension->GetList(kSupportedLocales, &supported_locales)) {
155 std::vector<std::string> browser_locales;
156 l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
157 &browser_locales);
158
159 size_t num_locales = supported_locales->GetSize();
160 bool locale_supported = false;
161 for (size_t j = 0; j < num_locales; j++) {
162 std::string current_locale;
163 if (supported_locales->GetString(j, &current_locale) &&
164 l10n_util::IsValidLocaleSyntax(current_locale)) {
165 current_locale = l10n_util::NormalizeLocale(current_locale);
166 if (std::find(browser_locales.begin(), browser_locales.end(),
167 current_locale) != browser_locales.end()) {
168 locale_supported = true;
169 break;
170 }
171 } else {
172 LOG(WARNING) << "Unrecognized locale '" << current_locale
173 << "' found as supported locale for extension: "
174 << extension_id;
175 }
176 }
177
178 if (!locale_supported) {
179 unsupported_extensions.insert(extension_id);
180 LOG(INFO) << "Skip installing (or uninstall) external extension: "
181 << extension_id << " because the extension doesn't support "
182 << "the browser locale.";
183 continue;
184 }
185 }
186
187 int creation_flags = creation_flags_;
188 bool is_bookmark_app;
189 if (extension->GetBoolean(kIsBookmarkApp, &is_bookmark_app) &&
190 is_bookmark_app) {
191 creation_flags |= Extension::FROM_BOOKMARK;
192 }
193
194 if (has_external_crx) {
195 if (crx_location_ == Extension::INVALID) {
196 LOG(WARNING) << "This provider does not support installing external "
197 << "extensions from crx files.";
198 continue;
199 }
200 if (external_crx.find(FilePath::kParentDirectory) !=
201 base::StringPiece::npos) {
202 LOG(WARNING) << "Path traversal not allowed in path: "
203 << external_crx.c_str();
204 continue;
205 }
206
207 // If the path is relative, and the provider has a base path,
208 // build the absolute path to the crx file.
209 FilePath path(external_crx);
210 if (!path.IsAbsolute()) {
211 FilePath base_path = loader_->GetBaseCrxFilePath();
212 if (base_path.empty()) {
213 LOG(WARNING) << "File path " << external_crx.c_str()
214 << " is relative. An absolute path is required.";
215 continue;
216 }
217 path = base_path.Append(external_crx);
218 }
219
220 scoped_ptr<Version> version;
221 version.reset(Version::GetVersionFromString(external_version));
222 if (!version.get()) {
223 LOG(WARNING) << "Malformed extension dictionary for extension: "
224 << extension_id.c_str() << ". Invalid version string \""
225 << external_version << "\".";
226 continue;
227 }
228 service_->OnExternalExtensionFileFound(extension_id, version.get(), path,
229 crx_location_, creation_flags,
230 auto_acknowledge_);
231 } else { // if (has_external_update_url)
232 CHECK(has_external_update_url); // Checking of keys above ensures this.
233 if (download_location_ == Extension::INVALID) {
234 LOG(WARNING) << "This provider does not support installing external "
235 << "extensions from update URLs.";
236 continue;
237 }
238 GURL update_url(external_update_url);
239 if (!update_url.is_valid()) {
240 LOG(WARNING) << "Malformed extension dictionary for extension: "
241 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
242 << " has value \"" << external_update_url
243 << "\", which is not a valid URL.";
244 continue;
245 }
246 service_->OnExternalExtensionUpdateUrlFound(
247 extension_id, update_url, download_location_);
248 }
249 }
250
251 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
252 it != unsupported_extensions.end(); ++it) {
253 // Remove extension for the list of know external extensions. The extension
254 // will be uninstalled later because provider doesn't provide it anymore.
255 prefs_->Remove(*it, NULL);
256 }
257
258 service_->OnExternalProviderReady(this);
259 }
260
261 void ExternalExtensionProviderImpl::ServiceShutdown() {
262 service_ = NULL;
263 }
264
265 bool ExternalExtensionProviderImpl::IsReady() const {
266 return ready_;
267 }
268
269 bool ExternalExtensionProviderImpl::HasExtension(
270 const std::string& id) const {
271 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
272 CHECK(prefs_.get());
273 CHECK(ready_);
274 return prefs_->HasKey(id);
275 }
276
277 bool ExternalExtensionProviderImpl::GetExtensionDetails(
278 const std::string& id, Extension::Location* location,
279 scoped_ptr<Version>* version) const {
280 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281 CHECK(prefs_.get());
282 CHECK(ready_);
283 DictionaryValue* extension = NULL;
284 if (!prefs_->GetDictionary(id, &extension))
285 return false;
286
287 Extension::Location loc = Extension::INVALID;
288 if (extension->HasKey(kExternalUpdateUrl)) {
289 loc = download_location_;
290
291 } else if (extension->HasKey(kExternalCrx)) {
292 loc = crx_location_;
293
294 std::string external_version;
295 if (!extension->GetString(kExternalVersion, &external_version))
296 return false;
297
298 if (version)
299 version->reset(Version::GetVersionFromString(external_version));
300
301 } else {
302 NOTREACHED(); // Chrome should not allow prefs to get into this state.
303 return false;
304 }
305
306 if (location)
307 *location = loc;
308
309 return true;
310 }
311
312 // static
313 void ExternalExtensionProviderImpl::CreateExternalProviders(
314 VisitorInterface* service,
315 Profile* profile,
316 ProviderCollection* provider_list) {
317
318 // On Mac OS, items in /Library/... should be written by the superuser.
319 // Check that all components of the path are writable by root only.
320 ExternalPrefExtensionLoader::Options check_admin_permissions_on_mac;
321 #if defined(OS_MACOSX)
322 check_admin_permissions_on_mac =
323 ExternalPrefExtensionLoader::ENSURE_PATH_CONTROLLED_BY_ADMIN;
324 #else
325 check_admin_permissions_on_mac = ExternalPrefExtensionLoader::NONE;
326 #endif
327
328 bool is_chromeos_demo_session = false;
329 int bundled_extension_creation_flags = Extension::NO_FLAGS;
330 #if defined(OS_CHROMEOS)
331 chromeos::UserManager* user_manager = chromeos::UserManager::Get();
332 is_chromeos_demo_session =
333 user_manager && user_manager->IsLoggedInAsDemoUser() &&
334 g_browser_process->browser_policy_connector()->GetDeviceMode() ==
335 policy::DEVICE_MODE_KIOSK;
336 bundled_extension_creation_flags = Extension::FROM_WEBSTORE;
337 #endif
338
339 if (!is_chromeos_demo_session) {
340 provider_list->push_back(
341 linked_ptr<ExternalExtensionProviderInterface>(
342 new ExternalExtensionProviderImpl(
343 service,
344 new ExternalPrefExtensionLoader(
345 chrome::DIR_EXTERNAL_EXTENSIONS,
346 check_admin_permissions_on_mac),
347 Extension::EXTERNAL_PREF,
348 Extension::EXTERNAL_PREF_DOWNLOAD,
349 bundled_extension_creation_flags)));
350 }
351
352 #if defined(OS_CHROMEOS) || defined (OS_MACOSX)
353 // Define a per-user source of external extensions.
354 // On Chrome OS, this serves as a source for OEM customization.
355 provider_list->push_back(
356 linked_ptr<ExternalExtensionProviderInterface>(
357 new ExternalExtensionProviderImpl(
358 service,
359 new ExternalPrefExtensionLoader(
360 chrome::DIR_USER_EXTERNAL_EXTENSIONS,
361 ExternalPrefExtensionLoader::NONE),
362 Extension::EXTERNAL_PREF,
363 Extension::EXTERNAL_PREF_DOWNLOAD,
364 Extension::NO_FLAGS)));
365 #endif
366 #if defined(OS_WIN)
367 provider_list->push_back(
368 linked_ptr<ExternalExtensionProviderInterface>(
369 new ExternalExtensionProviderImpl(
370 service,
371 new ExternalRegistryExtensionLoader,
372 Extension::EXTERNAL_REGISTRY,
373 Extension::INVALID,
374 Extension::NO_FLAGS)));
375 #endif
376
377 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
378 provider_list->push_back(
379 linked_ptr<ExternalExtensionProviderInterface>(
380 new ExternalExtensionProviderImpl(
381 service,
382 new ExternalPrefExtensionLoader(
383 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
384 ExternalPrefExtensionLoader::NONE),
385 Extension::EXTERNAL_PREF,
386 Extension::EXTERNAL_PREF_DOWNLOAD,
387 Extension::NO_FLAGS)));
388 #endif
389
390 provider_list->push_back(
391 linked_ptr<ExternalExtensionProviderInterface>(
392 new ExternalExtensionProviderImpl(
393 service,
394 new ExternalPolicyExtensionLoader(profile),
395 Extension::INVALID,
396 Extension::EXTERNAL_POLICY_DOWNLOAD,
397 Extension::NO_FLAGS)));
398
399 #if !defined(OS_CHROMEOS)
400 provider_list->push_back(
401 linked_ptr<ExternalExtensionProviderInterface>(
402 new default_apps::Provider(
403 profile,
404 service,
405 new ExternalPrefExtensionLoader(
406 chrome::DIR_DEFAULT_APPS,
407 ExternalPrefExtensionLoader::NONE),
408 Extension::EXTERNAL_PREF,
409 Extension::INVALID,
410 Extension::FROM_WEBSTORE)));
411 #endif
412
413 #if defined(OS_CHROMEOS)
414 policy::BrowserPolicyConnector* connector =
415 g_browser_process->browser_policy_connector();
416 if (is_chromeos_demo_session && connector->GetAppPackUpdater()) {
417 provider_list->push_back(
418 linked_ptr<ExternalExtensionProviderInterface>(
419 new ExternalExtensionProviderImpl(
420 service,
421 connector->GetAppPackUpdater()->CreateExternalExtensionLoader(),
422 Extension::EXTERNAL_PREF,
423 Extension::INVALID,
424 Extension::NO_FLAGS)));
425 }
426 #endif
427 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698