ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / extensions / external_provider_impl.cc
blob4e5ba79ca8157620d3587dd03ecb4c803f299264
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.
5 #include "chrome/browser/extensions/external_provider_impl.h"
7 #include <set>
8 #include <vector>
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/memory/linked_ptr.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "base/version.h"
18 #include "chrome/browser/app_mode/app_mode_utils.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/extension_management.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/external_component_loader.h"
23 #include "chrome/browser/extensions/external_policy_loader.h"
24 #include "chrome/browser/extensions/external_pref_loader.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "components/crx_file/id_util.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/browser/external_provider_interface.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/manifest.h"
34 #include "ui/base/l10n/l10n_util.h"
36 #if defined(OS_CHROMEOS)
37 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
38 #include "chrome/browser/chromeos/customization/customization_document.h"
39 #include "chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.h"
40 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
41 #include "chrome/browser/chromeos/policy/device_local_account.h"
42 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
43 #include "chrome/browser/chromeos/profiles/profile_helper.h"
44 #include "components/user_manager/user.h"
45 #else
46 #include "chrome/browser/extensions/default_apps.h"
47 #endif
49 #if defined(OS_WIN)
50 #include "chrome/browser/extensions/external_registry_loader_win.h"
51 #endif
53 using content::BrowserThread;
55 namespace extensions {
57 // Constants for keeping track of extension preferences in a dictionary.
58 const char ExternalProviderImpl::kInstallParam[] = "install_parameter";
59 const char ExternalProviderImpl::kExternalCrx[] = "external_crx";
60 const char ExternalProviderImpl::kExternalVersion[] = "external_version";
61 const char ExternalProviderImpl::kExternalUpdateUrl[] = "external_update_url";
62 const char ExternalProviderImpl::kIsBookmarkApp[] = "is_bookmark_app";
63 const char ExternalProviderImpl::kIsFromWebstore[] = "is_from_webstore";
64 const char ExternalProviderImpl::kKeepIfPresent[] = "keep_if_present";
65 const char ExternalProviderImpl::kWasInstalledByOem[] = "was_installed_by_oem";
66 const char ExternalProviderImpl::kSupportedLocales[] = "supported_locales";
67 const char ExternalProviderImpl::kMayBeUntrusted[] = "may_be_untrusted";
69 ExternalProviderImpl::ExternalProviderImpl(
70 VisitorInterface* service,
71 const scoped_refptr<ExternalLoader>& loader,
72 Profile* profile,
73 Manifest::Location crx_location,
74 Manifest::Location download_location,
75 int creation_flags)
76 : crx_location_(crx_location),
77 download_location_(download_location),
78 service_(service),
79 ready_(false),
80 loader_(loader),
81 profile_(profile),
82 creation_flags_(creation_flags),
83 auto_acknowledge_(false) {
84 loader_->Init(this);
87 ExternalProviderImpl::~ExternalProviderImpl() {
88 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 loader_->OwnerShutdown();
92 void ExternalProviderImpl::VisitRegisteredExtension() {
93 // The loader will call back to SetPrefs.
94 loader_->StartLoading();
97 void ExternalProviderImpl::SetPrefs(base::DictionaryValue* prefs) {
98 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
100 // Check if the service is still alive. It is possible that it went
101 // away while |loader_| was working on the FILE thread.
102 if (!service_) return;
104 prefs_.reset(prefs);
105 ready_ = true; // Queries for extensions are allowed from this point.
107 // Set of unsupported extensions that need to be deleted from prefs_.
108 std::set<std::string> unsupported_extensions;
110 // Notify ExtensionService about all the extensions this provider has.
111 for (base::DictionaryValue::Iterator i(*prefs_); !i.IsAtEnd(); i.Advance()) {
112 const std::string& extension_id = i.key();
113 const base::DictionaryValue* extension = NULL;
115 if (!crx_file::id_util::IdIsValid(extension_id)) {
116 LOG(WARNING) << "Malformed extension dictionary: key "
117 << extension_id.c_str() << " is not a valid id.";
118 continue;
121 if (!i.value().GetAsDictionary(&extension)) {
122 LOG(WARNING) << "Malformed extension dictionary: key "
123 << extension_id.c_str()
124 << " has a value that is not a dictionary.";
125 continue;
128 base::FilePath::StringType external_crx;
129 const base::Value* external_version_value = NULL;
130 std::string external_version;
131 std::string external_update_url;
133 bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
135 bool has_external_version = false;
136 if (extension->Get(kExternalVersion, &external_version_value)) {
137 if (external_version_value->IsType(base::Value::TYPE_STRING)) {
138 external_version_value->GetAsString(&external_version);
139 has_external_version = true;
140 } else {
141 LOG(WARNING) << "Malformed extension dictionary for extension: "
142 << extension_id.c_str() << ". " << kExternalVersion
143 << " value must be a string.";
144 continue;
148 bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
149 &external_update_url);
150 if (has_external_crx != has_external_version) {
151 LOG(WARNING) << "Malformed extension dictionary for extension: "
152 << extension_id.c_str() << ". " << kExternalCrx
153 << " and " << kExternalVersion << " must be used together.";
154 continue;
157 if (has_external_crx == has_external_update_url) {
158 LOG(WARNING) << "Malformed extension dictionary for extension: "
159 << extension_id.c_str() << ". Exactly one of the "
160 << "followng keys should be used: " << kExternalCrx
161 << ", " << kExternalUpdateUrl << ".";
162 continue;
165 // Check that extension supports current browser locale.
166 const base::ListValue* supported_locales = NULL;
167 if (extension->GetList(kSupportedLocales, &supported_locales)) {
168 std::vector<std::string> browser_locales;
169 l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
170 &browser_locales);
172 size_t num_locales = supported_locales->GetSize();
173 bool locale_supported = false;
174 for (size_t j = 0; j < num_locales; j++) {
175 std::string current_locale;
176 if (supported_locales->GetString(j, &current_locale) &&
177 l10n_util::IsValidLocaleSyntax(current_locale)) {
178 current_locale = l10n_util::NormalizeLocale(current_locale);
179 if (std::find(browser_locales.begin(), browser_locales.end(),
180 current_locale) != browser_locales.end()) {
181 locale_supported = true;
182 break;
184 } else {
185 LOG(WARNING) << "Unrecognized locale '" << current_locale
186 << "' found as supported locale for extension: "
187 << extension_id;
191 if (!locale_supported) {
192 unsupported_extensions.insert(extension_id);
193 VLOG(1) << "Skip installing (or uninstall) external extension: "
194 << extension_id << " because the extension doesn't support "
195 << "the browser locale.";
196 continue;
200 int creation_flags = creation_flags_;
201 bool is_bookmark_app;
202 if (extension->GetBoolean(kIsBookmarkApp, &is_bookmark_app) &&
203 is_bookmark_app) {
204 creation_flags |= Extension::FROM_BOOKMARK;
206 bool is_from_webstore = false;
207 if (extension->GetBoolean(kIsFromWebstore, &is_from_webstore) &&
208 is_from_webstore) {
209 creation_flags |= Extension::FROM_WEBSTORE;
211 bool keep_if_present = false;
212 if (extension->GetBoolean(kKeepIfPresent, &keep_if_present) &&
213 keep_if_present && profile_) {
214 ExtensionServiceInterface* extension_service =
215 ExtensionSystem::Get(profile_)->extension_service();
216 const Extension* extension = extension_service ?
217 extension_service->GetExtensionById(extension_id, true) : NULL;
218 if (!extension) {
219 VLOG(1) << "Skip installing (or uninstall) external extension: "
220 << extension_id << " because the extension should be kept "
221 << "only if it is already installed.";
222 continue;
225 bool was_installed_by_oem = false;
226 if (extension->GetBoolean(kWasInstalledByOem, &was_installed_by_oem) &&
227 was_installed_by_oem) {
228 creation_flags |= Extension::WAS_INSTALLED_BY_OEM;
230 bool may_be_untrusted = false;
231 if (extension->GetBoolean(kMayBeUntrusted, &may_be_untrusted) &&
232 may_be_untrusted) {
233 creation_flags |= Extension::MAY_BE_UNTRUSTED;
236 std::string install_parameter;
237 extension->GetString(kInstallParam, &install_parameter);
239 if (has_external_crx) {
240 if (crx_location_ == Manifest::INVALID_LOCATION) {
241 LOG(WARNING) << "This provider does not support installing external "
242 << "extensions from crx files.";
243 continue;
245 if (external_crx.find(base::FilePath::kParentDirectory) !=
246 base::StringPiece::npos) {
247 LOG(WARNING) << "Path traversal not allowed in path: "
248 << external_crx.c_str();
249 continue;
252 // If the path is relative, and the provider has a base path,
253 // build the absolute path to the crx file.
254 base::FilePath path(external_crx);
255 if (!path.IsAbsolute()) {
256 base::FilePath base_path = loader_->GetBaseCrxFilePath();
257 if (base_path.empty()) {
258 LOG(WARNING) << "File path " << external_crx.c_str()
259 << " is relative. An absolute path is required.";
260 continue;
262 path = base_path.Append(external_crx);
265 Version version(external_version);
266 if (!version.IsValid()) {
267 LOG(WARNING) << "Malformed extension dictionary for extension: "
268 << extension_id.c_str() << ". Invalid version string \""
269 << external_version << "\".";
270 continue;
272 service_->OnExternalExtensionFileFound(extension_id, &version, path,
273 crx_location_, creation_flags,
274 auto_acknowledge_);
275 } else { // if (has_external_update_url)
276 CHECK(has_external_update_url); // Checking of keys above ensures this.
277 if (download_location_ == Manifest::INVALID_LOCATION) {
278 LOG(WARNING) << "This provider does not support installing external "
279 << "extensions from update URLs.";
280 continue;
282 GURL update_url(external_update_url);
283 if (!update_url.is_valid()) {
284 LOG(WARNING) << "Malformed extension dictionary for extension: "
285 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
286 << " has value \"" << external_update_url
287 << "\", which is not a valid URL.";
288 continue;
290 service_->OnExternalExtensionUpdateUrlFound(extension_id,
291 install_parameter,
292 update_url,
293 download_location_,
294 creation_flags,
295 auto_acknowledge_);
299 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
300 it != unsupported_extensions.end(); ++it) {
301 // Remove extension for the list of know external extensions. The extension
302 // will be uninstalled later because provider doesn't provide it anymore.
303 prefs_->Remove(*it, NULL);
306 service_->OnExternalProviderReady(this);
309 void ExternalProviderImpl::ServiceShutdown() {
310 service_ = NULL;
313 bool ExternalProviderImpl::IsReady() const {
314 return ready_;
317 bool ExternalProviderImpl::HasExtension(
318 const std::string& id) const {
319 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
320 CHECK(prefs_.get());
321 CHECK(ready_);
322 return prefs_->HasKey(id);
325 bool ExternalProviderImpl::GetExtensionDetails(
326 const std::string& id, Manifest::Location* location,
327 scoped_ptr<Version>* version) const {
328 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
329 CHECK(prefs_.get());
330 CHECK(ready_);
331 base::DictionaryValue* extension = NULL;
332 if (!prefs_->GetDictionary(id, &extension))
333 return false;
335 Manifest::Location loc = Manifest::INVALID_LOCATION;
336 if (extension->HasKey(kExternalUpdateUrl)) {
337 loc = download_location_;
339 } else if (extension->HasKey(kExternalCrx)) {
340 loc = crx_location_;
342 std::string external_version;
343 if (!extension->GetString(kExternalVersion, &external_version))
344 return false;
346 if (version)
347 version->reset(new Version(external_version));
349 } else {
350 NOTREACHED(); // Chrome should not allow prefs to get into this state.
351 return false;
354 if (location)
355 *location = loc;
357 return true;
360 // static
361 void ExternalProviderImpl::CreateExternalProviders(
362 VisitorInterface* service,
363 Profile* profile,
364 ProviderCollection* provider_list) {
365 scoped_refptr<ExternalLoader> external_loader;
366 scoped_refptr<ExternalLoader> external_recommended_loader;
367 extensions::Manifest::Location crx_location = Manifest::INVALID_LOCATION;
368 #if defined(OS_CHROMEOS)
369 policy::BrowserPolicyConnectorChromeOS* connector =
370 g_browser_process->platform_part()->browser_policy_connector_chromeos();
371 bool is_chrome_os_public_session = false;
372 const user_manager::User* user =
373 chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
374 policy::DeviceLocalAccount::Type account_type;
375 if (user &&
376 connector->IsEnterpriseManaged() &&
377 policy::IsDeviceLocalAccountUser(user->email(), &account_type)) {
378 if (account_type == policy::DeviceLocalAccount::TYPE_PUBLIC_SESSION)
379 is_chrome_os_public_session = true;
380 policy::DeviceLocalAccountPolicyBroker* broker =
381 connector->GetDeviceLocalAccountPolicyService()->GetBrokerForUser(
382 user->email());
383 if (broker) {
384 external_loader = broker->extension_loader();
385 crx_location = Manifest::EXTERNAL_POLICY;
386 } else {
387 NOTREACHED();
389 } else {
390 external_loader = new ExternalPolicyLoader(
391 ExtensionManagementFactory::GetForBrowserContext(profile),
392 ExternalPolicyLoader::FORCED);
393 external_recommended_loader = new ExternalPolicyLoader(
394 ExtensionManagementFactory::GetForBrowserContext(profile),
395 ExternalPolicyLoader::RECOMMENDED);
397 #else
398 external_loader = new ExternalPolicyLoader(
399 ExtensionManagementFactory::GetForBrowserContext(profile),
400 ExternalPolicyLoader::FORCED);
401 external_recommended_loader = new ExternalPolicyLoader(
402 ExtensionManagementFactory::GetForBrowserContext(profile),
403 ExternalPolicyLoader::RECOMMENDED);
404 #endif
406 // Policies are mandatory so they can't be skipped with command line flag.
407 if (external_loader.get()) {
408 provider_list->push_back(
409 linked_ptr<ExternalProviderInterface>(
410 new ExternalProviderImpl(
411 service,
412 external_loader,
413 profile,
414 crx_location,
415 Manifest::EXTERNAL_POLICY_DOWNLOAD,
416 Extension::NO_FLAGS)));
419 // Load the KioskAppExternalProvider when running in kiosk mode.
420 if (chrome::IsRunningInForcedAppMode()) {
421 #if defined(OS_CHROMEOS)
422 chromeos::KioskAppManager* kiosk_app_manager =
423 chromeos::KioskAppManager::Get();
424 DCHECK(kiosk_app_manager);
425 if (kiosk_app_manager && !kiosk_app_manager->external_loader_created()) {
426 provider_list->push_back(linked_ptr<ExternalProviderInterface>(
427 new ExternalProviderImpl(service,
428 kiosk_app_manager->CreateExternalLoader(),
429 profile,
430 Manifest::EXTERNAL_PREF,
431 Manifest::INVALID_LOCATION,
432 Extension::NO_FLAGS)));
434 #endif
435 return;
438 // Extensions provided by recommended policies.
439 if (external_recommended_loader.get()) {
440 provider_list->push_back(linked_ptr<ExternalProviderInterface>(
441 new ExternalProviderImpl(service,
442 external_recommended_loader,
443 profile,
444 crx_location,
445 Manifest::EXTERNAL_PREF_DOWNLOAD,
446 Extension::NO_FLAGS)));
449 // In tests don't install extensions from default external sources.
450 // It would only slowdown tests and make them flaky.
451 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
452 switches::kDisableDefaultApps))
453 return;
455 // On Mac OS, items in /Library/... should be written by the superuser.
456 // Check that all components of the path are writable by root only.
457 ExternalPrefLoader::Options check_admin_permissions_on_mac;
458 #if defined(OS_MACOSX)
459 check_admin_permissions_on_mac =
460 ExternalPrefLoader::ENSURE_PATH_CONTROLLED_BY_ADMIN;
461 #else
462 check_admin_permissions_on_mac = ExternalPrefLoader::NONE;
463 #endif
465 #if !defined(OS_WIN)
466 int bundled_extension_creation_flags = Extension::NO_FLAGS;
467 #endif
468 #if defined(OS_CHROMEOS)
469 bundled_extension_creation_flags = Extension::FROM_WEBSTORE |
470 Extension::WAS_INSTALLED_BY_DEFAULT;
472 if (!is_chrome_os_public_session) {
473 int external_apps_path_id = profile->IsSupervised() ?
474 chrome::DIR_SUPERVISED_USERS_DEFAULT_APPS :
475 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS;
476 ExternalPrefLoader::Options pref_load_flags =
477 profile->IsNewProfile()
478 ? ExternalPrefLoader::DELAY_LOAD_UNTIL_PRIORITY_SYNC
479 : ExternalPrefLoader::NONE;
480 provider_list->push_back(
481 linked_ptr<ExternalProviderInterface>(new ExternalProviderImpl(
482 service, new ExternalPrefLoader(external_apps_path_id,
483 pref_load_flags, profile),
484 profile, Manifest::EXTERNAL_PREF, Manifest::EXTERNAL_PREF_DOWNLOAD,
485 bundled_extension_creation_flags)));
487 // OEM default apps.
488 int oem_extension_creation_flags =
489 bundled_extension_creation_flags | Extension::WAS_INSTALLED_BY_OEM;
490 chromeos::ServicesCustomizationDocument* customization =
491 chromeos::ServicesCustomizationDocument::GetInstance();
492 provider_list->push_back(linked_ptr<ExternalProviderInterface>(
493 new ExternalProviderImpl(service,
494 customization->CreateExternalLoader(profile),
495 profile,
496 Manifest::EXTERNAL_PREF,
497 Manifest::EXTERNAL_PREF_DOWNLOAD,
498 oem_extension_creation_flags)));
500 #elif defined(OS_LINUX)
501 if (!profile->IsLegacySupervised()) {
502 provider_list->push_back(
503 linked_ptr<ExternalProviderInterface>(
504 new ExternalProviderImpl(
505 service,
506 new ExternalPrefLoader(
507 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
508 ExternalPrefLoader::NONE,
509 NULL),
510 profile,
511 Manifest::EXTERNAL_PREF,
512 Manifest::EXTERNAL_PREF_DOWNLOAD,
513 bundled_extension_creation_flags)));
515 #endif
517 if (!profile->IsLegacySupervised()) {
518 #if defined(OS_WIN)
519 provider_list->push_back(
520 linked_ptr<ExternalProviderInterface>(
521 new ExternalProviderImpl(
522 service,
523 new ExternalRegistryLoader,
524 profile,
525 Manifest::EXTERNAL_REGISTRY,
526 Manifest::EXTERNAL_PREF_DOWNLOAD,
527 Extension::NO_FLAGS)));
528 #else
529 provider_list->push_back(
530 linked_ptr<ExternalProviderInterface>(
531 new ExternalProviderImpl(
532 service,
533 new ExternalPrefLoader(chrome::DIR_EXTERNAL_EXTENSIONS,
534 check_admin_permissions_on_mac,
535 NULL),
536 profile,
537 Manifest::EXTERNAL_PREF,
538 Manifest::EXTERNAL_PREF_DOWNLOAD,
539 bundled_extension_creation_flags)));
541 // Define a per-user source of external extensions.
542 #if defined(OS_MACOSX)
543 provider_list->push_back(
544 linked_ptr<ExternalProviderInterface>(
545 new ExternalProviderImpl(
546 service,
547 new ExternalPrefLoader(chrome::DIR_USER_EXTERNAL_EXTENSIONS,
548 ExternalPrefLoader::NONE,
549 NULL),
550 profile,
551 Manifest::EXTERNAL_PREF,
552 Manifest::EXTERNAL_PREF_DOWNLOAD,
553 Extension::NO_FLAGS)));
554 #endif
555 #endif
557 #if !defined(OS_CHROMEOS)
558 // The default apps are installed as INTERNAL but use the external
559 // extension installer codeflow.
560 provider_list->push_back(
561 linked_ptr<ExternalProviderInterface>(
562 new default_apps::Provider(
563 profile,
564 service,
565 new ExternalPrefLoader(chrome::DIR_DEFAULT_APPS,
566 ExternalPrefLoader::NONE,
567 NULL),
568 Manifest::INTERNAL,
569 Manifest::INTERNAL,
570 Extension::FROM_WEBSTORE |
571 Extension::WAS_INSTALLED_BY_DEFAULT)));
572 #endif
575 provider_list->push_back(
576 linked_ptr<ExternalProviderInterface>(
577 new ExternalProviderImpl(
578 service,
579 new ExternalComponentLoader(profile),
580 profile,
581 Manifest::INVALID_LOCATION,
582 Manifest::EXTERNAL_COMPONENT,
583 Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT)));
586 } // namespace extensions