ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / extensions / extension_management.cc
blobe9b922ff442568ecc542435b0cd43952b8cb6ca5
1 // Copyright 2014 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/extension_management.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/logging.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_util.h"
15 #include "base/version.h"
16 #include "chrome/browser/extensions/extension_management_constants.h"
17 #include "chrome/browser/extensions/extension_management_internal.h"
18 #include "chrome/browser/extensions/external_policy_loader.h"
19 #include "chrome/browser/extensions/external_provider_impl.h"
20 #include "chrome/browser/extensions/permissions_based_management_policy_provider.h"
21 #include "chrome/browser/extensions/standard_management_policy_provider.h"
22 #include "chrome/browser/profiles/incognito_helpers.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "components/crx_file/id_util.h"
25 #include "components/keyed_service/content/browser_context_dependency_manager.h"
26 #include "components/pref_registry/pref_registry_syncable.h"
27 #include "extensions/browser/pref_names.h"
28 #include "extensions/common/manifest_constants.h"
29 #include "extensions/common/permissions/api_permission_set.h"
30 #include "extensions/common/permissions/permission_set.h"
31 #include "extensions/common/url_pattern.h"
32 #include "url/gurl.h"
34 namespace extensions {
36 ExtensionManagement::ExtensionManagement(PrefService* pref_service)
37 : pref_service_(pref_service) {
38 pref_change_registrar_.Init(pref_service_);
39 base::Closure pref_change_callback = base::Bind(
40 &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this));
41 pref_change_registrar_.Add(pref_names::kInstallAllowList,
42 pref_change_callback);
43 pref_change_registrar_.Add(pref_names::kInstallDenyList,
44 pref_change_callback);
45 pref_change_registrar_.Add(pref_names::kInstallForceList,
46 pref_change_callback);
47 pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
48 pref_change_callback);
49 pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
50 pref_change_registrar_.Add(pref_names::kExtensionManagement,
51 pref_change_callback);
52 // Note that both |global_settings_| and |default_settings_| will be null
53 // before first call to Refresh(), so in order to resolve this, Refresh() must
54 // be called in the initialization of ExtensionManagement.
55 Refresh();
56 providers_.push_back(new StandardManagementPolicyProvider(this));
57 providers_.push_back(new PermissionsBasedManagementPolicyProvider(this));
60 ExtensionManagement::~ExtensionManagement() {
63 void ExtensionManagement::Shutdown() {
64 pref_change_registrar_.RemoveAll();
65 pref_service_ = nullptr;
68 void ExtensionManagement::AddObserver(Observer* observer) {
69 observer_list_.AddObserver(observer);
72 void ExtensionManagement::RemoveObserver(Observer* observer) {
73 observer_list_.RemoveObserver(observer);
76 std::vector<ManagementPolicy::Provider*> ExtensionManagement::GetProviders()
77 const {
78 return providers_.get();
81 bool ExtensionManagement::BlacklistedByDefault() const {
82 return default_settings_->installation_mode == INSTALLATION_BLOCKED;
85 ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
86 const Extension* extension) const {
87 // Check per-extension installation mode setting first.
88 auto iter_id = settings_by_id_.find(extension->id());
89 if (iter_id != settings_by_id_.end())
90 return iter_id->second->installation_mode;
91 std::string update_url;
92 // Check per-update-url installation mode setting.
93 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
94 &update_url)) {
95 auto iter_update_url = settings_by_update_url_.find(update_url);
96 if (iter_update_url != settings_by_update_url_.end())
97 return iter_update_url->second->installation_mode;
99 // Fall back to default installation mode setting.
100 return default_settings_->installation_mode;
103 scoped_ptr<base::DictionaryValue> ExtensionManagement::GetForceInstallList()
104 const {
105 scoped_ptr<base::DictionaryValue> install_list(new base::DictionaryValue());
106 for (SettingsIdMap::const_iterator it = settings_by_id_.begin();
107 it != settings_by_id_.end();
108 ++it) {
109 if (it->second->installation_mode == INSTALLATION_FORCED) {
110 ExternalPolicyLoader::AddExtension(
111 install_list.get(), it->first, it->second->update_url);
114 return install_list.Pass();
117 scoped_ptr<base::DictionaryValue>
118 ExtensionManagement::GetRecommendedInstallList() const {
119 scoped_ptr<base::DictionaryValue> install_list(new base::DictionaryValue());
120 for (SettingsIdMap::const_iterator it = settings_by_id_.begin();
121 it != settings_by_id_.end();
122 ++it) {
123 if (it->second->installation_mode == INSTALLATION_RECOMMENDED) {
124 ExternalPolicyLoader::AddExtension(
125 install_list.get(), it->first, it->second->update_url);
128 return install_list.Pass();
131 bool ExtensionManagement::IsInstallationExplicitlyAllowed(
132 const ExtensionId& id) const {
133 SettingsIdMap::const_iterator it = settings_by_id_.find(id);
134 // No settings explicitly specified for |id|.
135 if (it == settings_by_id_.end())
136 return false;
137 // Checks if the extension is on the automatically installed list or
138 // install white-list.
139 InstallationMode mode = it->second->installation_mode;
140 return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
141 mode == INSTALLATION_ALLOWED;
144 bool ExtensionManagement::IsOffstoreInstallAllowed(
145 const GURL& url,
146 const GURL& referrer_url) const {
147 // No allowed install sites specified, disallow by default.
148 if (!global_settings_->has_restricted_install_sources)
149 return false;
151 const URLPatternSet& url_patterns = global_settings_->install_sources;
153 if (!url_patterns.MatchesURL(url))
154 return false;
156 // The referrer URL must also be whitelisted, unless the URL has the file
157 // scheme (there's no referrer for those URLs).
158 return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url);
161 bool ExtensionManagement::IsAllowedManifestType(
162 Manifest::Type manifest_type) const {
163 if (!global_settings_->has_restricted_allowed_types)
164 return true;
165 const std::vector<Manifest::Type>& allowed_types =
166 global_settings_->allowed_types;
167 return std::find(allowed_types.begin(), allowed_types.end(), manifest_type) !=
168 allowed_types.end();
171 APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
172 const Extension* extension) const {
173 // Fetch per-extension blocked permissions setting.
174 auto iter_id = settings_by_id_.find(extension->id());
176 // Fetch per-update-url blocked permissions setting.
177 std::string update_url;
178 auto iter_update_url = settings_by_update_url_.end();
179 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
180 &update_url)) {
181 iter_update_url = settings_by_update_url_.find(update_url);
184 if (iter_id != settings_by_id_.end() &&
185 iter_update_url != settings_by_update_url_.end()) {
186 // Blocked permissions setting are specified in both per-extension and
187 // per-update-url settings, try to merge them.
188 APIPermissionSet merged;
189 APIPermissionSet::Union(iter_id->second->blocked_permissions,
190 iter_update_url->second->blocked_permissions,
191 &merged);
192 return merged;
194 // Check whether if in one of them, setting is specified.
195 if (iter_id != settings_by_id_.end())
196 return iter_id->second->blocked_permissions;
197 if (iter_update_url != settings_by_update_url_.end())
198 return iter_update_url->second->blocked_permissions;
199 // Fall back to the default blocked permissions setting.
200 return default_settings_->blocked_permissions;
203 scoped_refptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
204 const Extension* extension) const {
205 // Only api permissions are supported currently.
206 return scoped_refptr<const PermissionSet>(new PermissionSet(
207 GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
208 URLPatternSet(), URLPatternSet()));
211 bool ExtensionManagement::IsPermissionSetAllowed(
212 const Extension* extension,
213 scoped_refptr<const PermissionSet> perms) const {
214 for (const auto& blocked_api : GetBlockedAPIPermissions(extension)) {
215 if (perms->HasAPIPermission(blocked_api->id()))
216 return false;
218 return true;
221 bool ExtensionManagement::CheckMinimumVersion(
222 const Extension* extension,
223 std::string* required_version) const {
224 auto iter = settings_by_id_.find(extension->id());
225 // If there are no minimum version required for |extension|, return true.
226 if (iter == settings_by_id_.end() || !iter->second->minimum_version_required)
227 return true;
228 bool meets_requirement = extension->version()->CompareTo(
229 *iter->second->minimum_version_required) >= 0;
230 // Output a human readable version string for prompting if necessary.
231 if (!meets_requirement && required_version)
232 *required_version = iter->second->minimum_version_required->GetString();
233 return meets_requirement;
236 void ExtensionManagement::Refresh() {
237 // Load all extension management settings preferences.
238 const base::ListValue* allowed_list_pref =
239 static_cast<const base::ListValue*>(LoadPreference(
240 pref_names::kInstallAllowList, true, base::Value::TYPE_LIST));
241 // Allow user to use preference to block certain extensions. Note that policy
242 // managed forcelist or whitelist will always override this.
243 const base::ListValue* denied_list_pref =
244 static_cast<const base::ListValue*>(LoadPreference(
245 pref_names::kInstallDenyList, false, base::Value::TYPE_LIST));
246 const base::DictionaryValue* forced_list_pref =
247 static_cast<const base::DictionaryValue*>(LoadPreference(
248 pref_names::kInstallForceList, true, base::Value::TYPE_DICTIONARY));
249 const base::ListValue* install_sources_pref =
250 static_cast<const base::ListValue*>(LoadPreference(
251 pref_names::kAllowedInstallSites, true, base::Value::TYPE_LIST));
252 const base::ListValue* allowed_types_pref =
253 static_cast<const base::ListValue*>(LoadPreference(
254 pref_names::kAllowedTypes, true, base::Value::TYPE_LIST));
255 const base::DictionaryValue* dict_pref =
256 static_cast<const base::DictionaryValue*>(
257 LoadPreference(pref_names::kExtensionManagement,
258 true,
259 base::Value::TYPE_DICTIONARY));
261 // Reset all settings.
262 global_settings_.reset(new internal::GlobalSettings());
263 settings_by_id_.clear();
264 default_settings_.reset(new internal::IndividualSettings());
266 // Parse default settings.
267 const base::StringValue wildcard("*");
268 if (denied_list_pref &&
269 denied_list_pref->Find(wildcard) != denied_list_pref->end()) {
270 default_settings_->installation_mode = INSTALLATION_BLOCKED;
273 const base::DictionaryValue* subdict = NULL;
274 if (dict_pref &&
275 dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) {
276 if (!default_settings_->Parse(
277 subdict, internal::IndividualSettings::SCOPE_DEFAULT)) {
278 LOG(WARNING) << "Default extension management settings parsing error.";
279 default_settings_->Reset();
282 // Settings from new preference have higher priority over legacy ones.
283 const base::ListValue* list_value = NULL;
284 if (subdict->GetList(schema_constants::kInstallSources, &list_value))
285 install_sources_pref = list_value;
286 if (subdict->GetList(schema_constants::kAllowedTypes, &list_value))
287 allowed_types_pref = list_value;
290 // Parse legacy preferences.
291 ExtensionId id;
293 if (allowed_list_pref) {
294 for (base::ListValue::const_iterator it = allowed_list_pref->begin();
295 it != allowed_list_pref->end(); ++it) {
296 if ((*it)->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
297 AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
301 if (denied_list_pref) {
302 for (base::ListValue::const_iterator it = denied_list_pref->begin();
303 it != denied_list_pref->end(); ++it) {
304 if ((*it)->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
305 AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
309 if (forced_list_pref) {
310 std::string update_url;
311 for (base::DictionaryValue::Iterator it(*forced_list_pref); !it.IsAtEnd();
312 it.Advance()) {
313 if (!crx_file::id_util::IdIsValid(it.key()))
314 continue;
315 const base::DictionaryValue* dict_value = NULL;
316 if (it.value().GetAsDictionary(&dict_value) &&
317 dict_value->GetStringWithoutPathExpansion(
318 ExternalProviderImpl::kExternalUpdateUrl, &update_url)) {
319 internal::IndividualSettings* by_id = AccessById(it.key());
320 by_id->installation_mode = INSTALLATION_FORCED;
321 by_id->update_url = update_url;
326 if (install_sources_pref) {
327 global_settings_->has_restricted_install_sources = true;
328 for (base::ListValue::const_iterator it = install_sources_pref->begin();
329 it != install_sources_pref->end(); ++it) {
330 std::string url_pattern;
331 if ((*it)->GetAsString(&url_pattern)) {
332 URLPattern entry(URLPattern::SCHEME_ALL);
333 if (entry.Parse(url_pattern) == URLPattern::PARSE_SUCCESS) {
334 global_settings_->install_sources.AddPattern(entry);
335 } else {
336 LOG(WARNING) << "Invalid URL pattern in for preference "
337 << pref_names::kAllowedInstallSites << ": "
338 << url_pattern << ".";
344 if (allowed_types_pref) {
345 global_settings_->has_restricted_allowed_types = true;
346 for (base::ListValue::const_iterator it = allowed_types_pref->begin();
347 it != allowed_types_pref->end(); ++it) {
348 int int_value;
349 std::string string_value;
350 if ((*it)->GetAsInteger(&int_value) && int_value >= 0 &&
351 int_value < Manifest::Type::NUM_LOAD_TYPES) {
352 global_settings_->allowed_types.push_back(
353 static_cast<Manifest::Type>(int_value));
354 } else if ((*it)->GetAsString(&string_value)) {
355 Manifest::Type manifest_type =
356 schema_constants::GetManifestType(string_value);
357 if (manifest_type != Manifest::TYPE_UNKNOWN)
358 global_settings_->allowed_types.push_back(manifest_type);
363 if (dict_pref) {
364 // Parse new extension management preference.
365 for (base::DictionaryValue::Iterator iter(*dict_pref); !iter.IsAtEnd();
366 iter.Advance()) {
367 if (iter.key() == schema_constants::kWildcard)
368 continue;
369 if (!iter.value().GetAsDictionary(&subdict))
370 continue;
371 if (StartsWithASCII(iter.key(), schema_constants::kUpdateUrlPrefix,
372 true)) {
373 const std::string& update_url =
374 iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
375 if (!GURL(update_url).is_valid()) {
376 LOG(WARNING) << "Invalid update URL: " << update_url << ".";
377 continue;
379 internal::IndividualSettings* by_update_url =
380 AccessByUpdateUrl(update_url);
381 if (!by_update_url->Parse(
382 subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
383 settings_by_update_url_.erase(update_url);
384 LOG(WARNING) << "Malformed Extension Management settings for "
385 "extensions with update url: " << update_url << ".";
387 } else {
388 const std::string& extension_id = iter.key();
389 if (!crx_file::id_util::IdIsValid(extension_id)) {
390 LOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
391 continue;
393 internal::IndividualSettings* by_id = AccessById(extension_id);
394 if (!by_id->Parse(subdict,
395 internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
396 settings_by_id_.erase(extension_id);
397 LOG(WARNING) << "Malformed Extension Management settings for "
398 << extension_id << ".";
405 const base::Value* ExtensionManagement::LoadPreference(
406 const char* pref_name,
407 bool force_managed,
408 base::Value::Type expected_type) {
409 if (!pref_service_)
410 return nullptr;
411 const PrefService::Preference* pref =
412 pref_service_->FindPreference(pref_name);
413 if (pref && !pref->IsDefaultValue() &&
414 (!force_managed || pref->IsManaged())) {
415 const base::Value* value = pref->GetValue();
416 if (value && value->IsType(expected_type))
417 return value;
419 return nullptr;
422 void ExtensionManagement::OnExtensionPrefChanged() {
423 Refresh();
424 NotifyExtensionManagementPrefChanged();
427 void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
428 FOR_EACH_OBSERVER(
429 Observer, observer_list_, OnExtensionManagementSettingsChanged());
432 internal::IndividualSettings* ExtensionManagement::AccessById(
433 const ExtensionId& id) {
434 DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id;
435 SettingsIdMap::iterator it = settings_by_id_.find(id);
436 if (it == settings_by_id_.end()) {
437 scoped_ptr<internal::IndividualSettings> settings(
438 new internal::IndividualSettings(default_settings_.get()));
439 it = settings_by_id_.add(id, settings.Pass()).first;
441 return it->second;
444 internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
445 const std::string& update_url) {
446 DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
447 SettingsUpdateUrlMap::iterator it = settings_by_update_url_.find(update_url);
448 if (it == settings_by_update_url_.end()) {
449 scoped_ptr<internal::IndividualSettings> settings(
450 new internal::IndividualSettings(default_settings_.get()));
451 it = settings_by_update_url_.add(update_url, settings.Pass()).first;
453 return it->second;
456 ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(
457 content::BrowserContext* context) {
458 return static_cast<ExtensionManagement*>(
459 GetInstance()->GetServiceForBrowserContext(context, true));
462 ExtensionManagementFactory* ExtensionManagementFactory::GetInstance() {
463 return Singleton<ExtensionManagementFactory>::get();
466 ExtensionManagementFactory::ExtensionManagementFactory()
467 : BrowserContextKeyedServiceFactory(
468 "ExtensionManagement",
469 BrowserContextDependencyManager::GetInstance()) {
472 ExtensionManagementFactory::~ExtensionManagementFactory() {
475 KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor(
476 content::BrowserContext* context) const {
477 return new ExtensionManagement(
478 Profile::FromBrowserContext(context)->GetPrefs());
481 content::BrowserContext* ExtensionManagementFactory::GetBrowserContextToUse(
482 content::BrowserContext* context) const {
483 return chrome::GetBrowserContextRedirectedInIncognito(context);
486 void ExtensionManagementFactory::RegisterProfilePrefs(
487 user_prefs::PrefRegistrySyncable* user_prefs) {
488 user_prefs->RegisterDictionaryPref(
489 pref_names::kExtensionManagement,
490 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
493 } // namespace extensions