diff options
Diffstat (limited to 'chrome')
7 files changed, 358 insertions, 295 deletions
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc index 1ecca8d..33b066b 100644 --- a/chrome/browser/extensions/extension_management.cc +++ b/chrome/browser/extensions/extension_management.cc @@ -4,12 +4,17 @@ #include "chrome/browser/extensions/extension_management.h" +#include <algorithm> +#include <string> +#include <vector> + #include "base/bind.h" #include "base/bind_helpers.h" #include "base/logging.h" #include "base/prefs/pref_service.h" #include "base/strings/string_util.h" #include "chrome/browser/extensions/extension_management_constants.h" +#include "chrome/browser/extensions/extension_management_internal.h" #include "chrome/browser/extensions/external_policy_loader.h" #include "chrome/browser/extensions/external_provider_impl.h" #include "chrome/browser/extensions/standard_management_policy_provider.h" @@ -24,97 +29,6 @@ namespace extensions { -namespace { - -const char kMalformedPreferenceWarning[] = - "Malformed extension management preference."; - -enum Scope { - // Parses the default settings. - SCOPE_DEFAULT = 0, - // Parses the settings for an extension with specified extension ID. - SCOPE_INDIVIDUAL, -}; - -// Parse the individual settings for |settings|. |dict| is the a -// sub-dictionary in extension management preference and |scope| represents -// the applicable range of the settings, a single extension, a group of -// extensions or default settings. -// Note that in case of parsing errors, |settings| will NOT be left untouched. -bool ParseIndividualSettings( - const base::DictionaryValue* dict, - Scope scope, - ExtensionManagement::IndividualSettings* settings) { - std::string installation_mode; - if (dict->GetStringWithoutPathExpansion(schema_constants::kInstallationMode, - &installation_mode)) { - if (installation_mode == schema_constants::kAllowed) { - settings->installation_mode = ExtensionManagement::INSTALLATION_ALLOWED; - } else if (installation_mode == schema_constants::kBlocked) { - settings->installation_mode = ExtensionManagement::INSTALLATION_BLOCKED; - } else if (installation_mode == schema_constants::kForceInstalled) { - settings->installation_mode = ExtensionManagement::INSTALLATION_FORCED; - } else if (installation_mode == schema_constants::kNormalInstalled) { - settings->installation_mode = - ExtensionManagement::INSTALLATION_RECOMMENDED; - } else { - // Invalid value for 'installation_mode'. - LOG(WARNING) << kMalformedPreferenceWarning; - return false; - } - } - - if (settings->installation_mode == ExtensionManagement::INSTALLATION_FORCED || - settings->installation_mode == - ExtensionManagement::INSTALLATION_RECOMMENDED) { - if (scope != SCOPE_INDIVIDUAL) { - // Only individual extensions are allowed to be automatically installed. - LOG(WARNING) << kMalformedPreferenceWarning; - return false; - } - std::string update_url; - if (dict->GetStringWithoutPathExpansion(schema_constants::kUpdateUrl, - &update_url) && - GURL(update_url).is_valid()) { - settings->update_url = update_url; - } else { - // No valid update URL for extension. - LOG(WARNING) << kMalformedPreferenceWarning; - return false; - } - } - - return true; -} - -} // namespace - -ExtensionManagement::IndividualSettings::IndividualSettings() { - Reset(); -} - -ExtensionManagement::IndividualSettings::~IndividualSettings() { -} - -void ExtensionManagement::IndividualSettings::Reset() { - installation_mode = ExtensionManagement::INSTALLATION_ALLOWED; - update_url.clear(); -} - -ExtensionManagement::GlobalSettings::GlobalSettings() { - Reset(); -} - -ExtensionManagement::GlobalSettings::~GlobalSettings() { -} - -void ExtensionManagement::GlobalSettings::Reset() { - has_restricted_install_sources = false; - install_sources.ClearPatterns(); - has_restricted_allowed_types = false; - allowed_types.clear(); -} - ExtensionManagement::ExtensionManagement(PrefService* pref_service) : pref_service_(pref_service) { pref_change_registrar_.Init(pref_service_); @@ -131,6 +45,9 @@ ExtensionManagement::ExtensionManagement(PrefService* pref_service) pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback); pref_change_registrar_.Add(pref_names::kExtensionManagement, pref_change_callback); + // Note that both |global_settings_| and |default_settings_| will be null + // before first call to Refresh(), so in order to resolve this, Refresh() must + // be called in the initialization of ExtensionManagement. Refresh(); provider_.reset(new StandardManagementPolicyProvider(this)); } @@ -146,12 +63,17 @@ void ExtensionManagement::RemoveObserver(Observer* observer) { observer_list_.RemoveObserver(observer); } -ManagementPolicy::Provider* ExtensionManagement::GetProvider() { +ManagementPolicy::Provider* ExtensionManagement::GetProvider() const { return provider_.get(); } -bool ExtensionManagement::BlacklistedByDefault() { - return default_settings_.installation_mode == INSTALLATION_BLOCKED; +bool ExtensionManagement::BlacklistedByDefault() const { + return default_settings_->installation_mode == INSTALLATION_BLOCKED; +} + +ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode( + const ExtensionId& id) const { + return ReadById(id)->installation_mode; } scoped_ptr<base::DictionaryValue> ExtensionManagement::GetForceInstallList() @@ -160,26 +82,26 @@ scoped_ptr<base::DictionaryValue> ExtensionManagement::GetForceInstallList() for (SettingsIdMap::const_iterator it = settings_by_id_.begin(); it != settings_by_id_.end(); ++it) { - if (it->second.installation_mode == INSTALLATION_FORCED) { + if (it->second->installation_mode == INSTALLATION_FORCED) { ExternalPolicyLoader::AddExtension( - forcelist.get(), it->first, it->second.update_url); + forcelist.get(), it->first, it->second->update_url); } } return forcelist.Pass(); } bool ExtensionManagement::IsInstallationAllowed(const ExtensionId& id) const { - return ReadById(id).installation_mode != INSTALLATION_BLOCKED; + return ReadById(id)->installation_mode != INSTALLATION_BLOCKED; } -bool ExtensionManagement::IsOffstoreInstallAllowed(const GURL& url, - const GURL& referrer_url) { +bool ExtensionManagement::IsOffstoreInstallAllowed( + const GURL& url, + const GURL& referrer_url) const { // No allowed install sites specified, disallow by default. - if (!global_settings_.has_restricted_install_sources) + if (!global_settings_->has_restricted_install_sources) return false; - const extensions::URLPatternSet& url_patterns = - global_settings_.install_sources; + const URLPatternSet& url_patterns = global_settings_->install_sources; if (!url_patterns.MatchesURL(url)) return false; @@ -189,18 +111,14 @@ bool ExtensionManagement::IsOffstoreInstallAllowed(const GURL& url, return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url); } -const ExtensionManagement::IndividualSettings& ExtensionManagement::ReadById( - const ExtensionId& id) const { - DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id; - SettingsIdMap::const_iterator it = settings_by_id_.find(id); - if (it != settings_by_id_.end()) - return it->second; - return default_settings_; -} - -const ExtensionManagement::GlobalSettings& -ExtensionManagement::ReadGlobalSettings() const { - return global_settings_; +bool ExtensionManagement::IsAllowedManifestType( + Manifest::Type manifest_type) const { + if (!global_settings_->has_restricted_allowed_types) + return true; + const std::vector<Manifest::Type>& allowed_types = + global_settings_->allowed_types; + return std::find(allowed_types.begin(), allowed_types.end(), manifest_type) != + allowed_types.end(); } void ExtensionManagement::Refresh() { @@ -229,23 +147,24 @@ void ExtensionManagement::Refresh() { base::Value::TYPE_DICTIONARY)); // Reset all settings. - global_settings_.Reset(); + global_settings_.reset(new internal::GlobalSettings()); settings_by_id_.clear(); - default_settings_.Reset(); + default_settings_.reset(new internal::IndividualSettings()); // Parse default settings. const base::StringValue wildcard("*"); if (denied_list_pref && denied_list_pref->Find(wildcard) != denied_list_pref->end()) { - default_settings_.installation_mode = INSTALLATION_BLOCKED; + default_settings_->installation_mode = INSTALLATION_BLOCKED; } const base::DictionaryValue* subdict = NULL; if (dict_pref && dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) { - if (!ParseIndividualSettings(subdict, SCOPE_DEFAULT, &default_settings_)) { + if (!default_settings_->Parse( + subdict, internal::IndividualSettings::SCOPE_DEFAULT)) { LOG(WARNING) << "Default extension management settings parsing error."; - default_settings_.Reset(); + default_settings_->Reset(); } // Settings from new preference have higher priority over legacy ones. @@ -285,7 +204,7 @@ void ExtensionManagement::Refresh() { if (it.value().GetAsDictionary(&dict_value) && dict_value->GetStringWithoutPathExpansion( ExternalProviderImpl::kExternalUpdateUrl, &update_url)) { - IndividualSettings* by_id = AccessById(it.key()); + internal::IndividualSettings* by_id = AccessById(it.key()); by_id->installation_mode = INSTALLATION_FORCED; by_id->update_url = update_url; } @@ -293,14 +212,14 @@ void ExtensionManagement::Refresh() { } if (install_sources_pref) { - global_settings_.has_restricted_install_sources = true; + global_settings_->has_restricted_install_sources = true; for (base::ListValue::const_iterator it = install_sources_pref->begin(); it != install_sources_pref->end(); ++it) { std::string url_pattern; if ((*it)->GetAsString(&url_pattern)) { URLPattern entry(URLPattern::SCHEME_ALL); if (entry.Parse(url_pattern) == URLPattern::PARSE_SUCCESS) { - global_settings_.install_sources.AddPattern(entry); + global_settings_->install_sources.AddPattern(entry); } else { LOG(WARNING) << "Invalid URL pattern in for preference " << pref_names::kAllowedInstallSites << ": " @@ -311,20 +230,20 @@ void ExtensionManagement::Refresh() { } if (allowed_types_pref) { - global_settings_.has_restricted_allowed_types = true; + global_settings_->has_restricted_allowed_types = true; for (base::ListValue::const_iterator it = allowed_types_pref->begin(); it != allowed_types_pref->end(); ++it) { int int_value; std::string string_value; if ((*it)->GetAsInteger(&int_value) && int_value >= 0 && int_value < Manifest::Type::NUM_LOAD_TYPES) { - global_settings_.allowed_types.push_back( + global_settings_->allowed_types.push_back( static_cast<Manifest::Type>(int_value)); } else if ((*it)->GetAsString(&string_value)) { Manifest::Type manifest_type = schema_constants::GetManifestType(string_value); if (manifest_type != Manifest::TYPE_UNKNOWN) - global_settings_.allowed_types.push_back(manifest_type); + global_settings_->allowed_types.push_back(manifest_type); } } } @@ -335,20 +254,19 @@ void ExtensionManagement::Refresh() { iter.Advance()) { if (iter.key() == schema_constants::kWildcard) continue; - if (!iter.value().GetAsDictionary(&subdict)) { - LOG(WARNING) << kMalformedPreferenceWarning; + if (!iter.value().GetAsDictionary(&subdict)) continue; - } if (StartsWithASCII(iter.key(), schema_constants::kUpdateUrlPrefix, true)) continue; const std::string& extension_id = iter.key(); if (!crx_file::id_util::IdIsValid(extension_id)) { - LOG(WARNING) << kMalformedPreferenceWarning; + LOG(WARNING) << "Invalid extension ID : " << extension_id << "."; continue; } - IndividualSettings* by_id = AccessById(extension_id); - if (!ParseIndividualSettings(subdict, SCOPE_INDIVIDUAL, by_id)) { - settings_by_id_.erase(settings_by_id_.find(extension_id)); + internal::IndividualSettings* by_id = AccessById(extension_id); + if (!by_id->Parse(subdict, + internal::IndividualSettings::SCOPE_INDIVIDUAL)) { + settings_by_id_.erase(extension_id); LOG(WARNING) << "Malformed Extension Management settings for " << extension_id << "."; } @@ -381,13 +299,30 @@ void ExtensionManagement::NotifyExtensionManagementPrefChanged() { Observer, observer_list_, OnExtensionManagementSettingsChanged()); } -ExtensionManagement::IndividualSettings* ExtensionManagement::AccessById( +const internal::IndividualSettings* ExtensionManagement::ReadById( + const ExtensionId& id) const { + DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id; + SettingsIdMap::const_iterator it = settings_by_id_.find(id); + if (it != settings_by_id_.end()) + return it->second; + return default_settings_.get(); +} + +const internal::GlobalSettings* ExtensionManagement::ReadGlobalSettings() + const { + return global_settings_.get(); +} + +internal::IndividualSettings* ExtensionManagement::AccessById( const ExtensionId& id) { DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id; SettingsIdMap::iterator it = settings_by_id_.find(id); - if (it == settings_by_id_.end()) - it = settings_by_id_.insert(std::make_pair(id, default_settings_)).first; - return &it->second; + if (it == settings_by_id_.end()) { + scoped_ptr<internal::IndividualSettings> settings( + new internal::IndividualSettings(*default_settings_)); + it = settings_by_id_.add(id, settings.Pass()).first; + } + return it->second; } ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext( diff --git a/chrome/browser/extensions/extension_management.h b/chrome/browser/extensions/extension_management.h index d7d1466..5cea880 100644 --- a/chrome/browser/extensions/extension_management.h +++ b/chrome/browser/extensions/extension_management.h @@ -5,10 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGEMENT_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGEMENT_H_ -#include <map> -#include <string> -#include <vector> - +#include "base/containers/scoped_ptr_hash_map.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" @@ -20,7 +17,6 @@ #include "extensions/browser/management_policy.h" #include "extensions/common/extension.h" #include "extensions/common/manifest.h" -#include "extensions/common/url_pattern_set.h" class GURL; class PrefService; @@ -31,6 +27,13 @@ class BrowserContext; namespace extensions { +namespace internal { + +struct IndividualSettings; +struct GlobalSettings; + +} // namespace internal + // Tracks the management policies that affect extensions and provides interfaces // for observing and obtaining the global settings for all extensions, as well // as per-extension settings. @@ -41,7 +44,7 @@ class ExtensionManagement : public KeyedService { public: virtual ~Observer() {} - // Will be called when an extension management preference changes. + // Called when the extension management settings change. virtual void OnExtensionManagementSettingsChanged() = 0; }; @@ -59,48 +62,6 @@ class ExtensionManagement : public KeyedService { INSTALLATION_RECOMMENDED, }; - // Class to hold extension management settings for one or a group of - // extensions. Settings can be applied to an individual extension identified - // by an ID, a group of extensions with specific |update_url| or all - // extensions at once. - struct IndividualSettings { - IndividualSettings(); - ~IndividualSettings(); - - void Reset(); - - // Extension installation mode. Setting this to INSTALLATION_FORCED or - // INSTALLATION_RECOMMENDED will enable extension auto-loading (only - // applicable to single extension), and in this case the |update_url| must - // be specified, containing the update URL for this extension. - // Note that |update_url| will be ignored for INSTALLATION_ALLOWED and - // INSTALLATION_BLOCKED installation mode. - // These settings will override the default settings, and unspecified - // settings will take value from default settings. - InstallationMode installation_mode; - std::string update_url; - }; - - // Global extension management settings, applicable to all extensions. - struct GlobalSettings { - GlobalSettings(); - ~GlobalSettings(); - - void Reset(); - - // Settings specifying which URLs are allowed to install extensions, will be - // enforced only if |has_restricted_install_sources| is set to true. - URLPatternSet install_sources; - bool has_restricted_install_sources; - - // Settings specifying all allowed app/extension types, will be enforced - // only of |has_restricted_allowed_types| is set to true. - std::vector<Manifest::Type> allowed_types; - bool has_restricted_allowed_types; - }; - - typedef std::map<ExtensionId, IndividualSettings> SettingsIdMap; - explicit ExtensionManagement(PrefService* pref_service); virtual ~ExtensionManagement(); @@ -109,12 +70,15 @@ class ExtensionManagement : public KeyedService { // Get the ManagementPolicy::Provider controlled by extension management // policy settings. - ManagementPolicy::Provider* GetProvider(); + ManagementPolicy::Provider* GetProvider() const; // Checks if extensions are blacklisted by default, by policy. When true, // this means that even extensions without an ID should be blacklisted (e.g. // from the command line, or when loaded as an unpacked extension). - bool BlacklistedByDefault(); + bool BlacklistedByDefault() const; + + // Returns installation mode for an extension. + InstallationMode GetInstallationMode(const ExtensionId& id) const; // Returns the force install list, in format specified by // ExternalPolicyLoader::AddExtension(). @@ -124,16 +88,18 @@ class ExtensionManagement : public KeyedService { bool IsInstallationAllowed(const ExtensionId& id) const; // Returns true if an extension download should be allowed to proceed. - bool IsOffstoreInstallAllowed(const GURL& url, const GURL& referrer_url); - - // Helper function to read |settings_by_id_| with |id| as key. Returns a - // constant reference to default settings if |id| does not exist. - const IndividualSettings& ReadById(const ExtensionId& id) const; + bool IsOffstoreInstallAllowed(const GURL& url, + const GURL& referrer_url) const; - // Returns a constant reference to |global_settings_|. - const GlobalSettings& ReadGlobalSettings() const; + // Returns true if an extension with manifest type |manifest_type| is + // allowed to be installed. + bool IsAllowedManifestType(Manifest::Type manifest_type) const; private: + typedef base::ScopedPtrHashMap<ExtensionId, internal::IndividualSettings> + SettingsIdMap; + friend class ExtensionManagementServiceTest; + // Load all extension management preferences from |pref_service|, and // refresh the settings. void Refresh(); @@ -149,10 +115,17 @@ class ExtensionManagement : public KeyedService { void OnExtensionPrefChanged(); void NotifyExtensionManagementPrefChanged(); + // Helper function to read |settings_by_id_| with |id| as key. Returns a + // constant reference to default settings if |id| does not exist. + const internal::IndividualSettings* ReadById(const ExtensionId& id) const; + + // Returns a constant reference to |global_settings_|. + const internal::GlobalSettings* ReadGlobalSettings() const; + // Helper function to access |settings_by_id_| with |id| as key. // Adds a new IndividualSettings entry to |settings_by_id_| if none exists for // |id| yet. - IndividualSettings* AccessById(const ExtensionId& id); + internal::IndividualSettings* AccessById(const ExtensionId& id); // A map containing all IndividualSettings applied to an individual extension // identified by extension ID. The extension ID is used as index key of the @@ -167,10 +140,10 @@ class ExtensionManagement : public KeyedService { // URL), all unspecified part will take value from |default_settings_|. // For all other extensions, all settings from |default_settings_| will be // enforced. - IndividualSettings default_settings_; + scoped_ptr<internal::IndividualSettings> default_settings_; // Extension settings applicable to all extensions. - GlobalSettings global_settings_; + scoped_ptr<internal::GlobalSettings> global_settings_; PrefService* pref_service_; diff --git a/chrome/browser/extensions/extension_management_internal.cc b/chrome/browser/extensions/extension_management_internal.cc new file mode 100644 index 0000000..73bd132 --- /dev/null +++ b/chrome/browser/extensions/extension_management_internal.cc @@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/extension_management_internal.h" + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_management_constants.h" +#include "extensions/common/url_pattern_set.h" +#include "url/gurl.h" + +namespace extensions { + +namespace internal { + +namespace { +const char kMalformedPreferenceWarning[] = + "Malformed extension management preference."; +} // namespace + +IndividualSettings::IndividualSettings() { + Reset(); +} + +IndividualSettings::~IndividualSettings() { +} + +bool IndividualSettings::Parse(const base::DictionaryValue* dict, + ParsingScope scope) { + std::string installation_mode_str; + if (dict->GetStringWithoutPathExpansion(schema_constants::kInstallationMode, + &installation_mode_str)) { + if (installation_mode_str == schema_constants::kAllowed) { + installation_mode = ExtensionManagement::INSTALLATION_ALLOWED; + } else if (installation_mode_str == schema_constants::kBlocked) { + installation_mode = ExtensionManagement::INSTALLATION_BLOCKED; + } else if (installation_mode_str == schema_constants::kForceInstalled) { + installation_mode = ExtensionManagement::INSTALLATION_FORCED; + } else if (installation_mode_str == schema_constants::kNormalInstalled) { + installation_mode = ExtensionManagement::INSTALLATION_RECOMMENDED; + } else { + // Invalid value for 'installation_mode'. + LOG(WARNING) << kMalformedPreferenceWarning; + return false; + } + + // Only proceed to fetch update url if force or recommended install mode + // is set. + if (installation_mode == ExtensionManagement::INSTALLATION_FORCED || + installation_mode == ExtensionManagement::INSTALLATION_RECOMMENDED) { + if (scope != SCOPE_INDIVIDUAL) { + // Only individual extensions are allowed to be automatically installed. + LOG(WARNING) << kMalformedPreferenceWarning; + return false; + } + std::string update_url_str; + if (dict->GetStringWithoutPathExpansion(schema_constants::kUpdateUrl, + &update_url_str) && + GURL(update_url_str).is_valid()) { + update_url = update_url_str; + } else { + // No valid update URL for extension. + LOG(WARNING) << kMalformedPreferenceWarning; + return false; + } + } + } + + return true; +} + +void IndividualSettings::Reset() { + installation_mode = ExtensionManagement::INSTALLATION_ALLOWED; + update_url.clear(); +} + +GlobalSettings::GlobalSettings() { + Reset(); +} + +GlobalSettings::~GlobalSettings() { +} + +void GlobalSettings::Reset() { + has_restricted_install_sources = false; + install_sources.ClearPatterns(); + has_restricted_allowed_types = false; + allowed_types.clear(); +} + +} // namespace internal + +} // namespace extensions diff --git a/chrome/browser/extensions/extension_management_internal.h b/chrome/browser/extensions/extension_management_internal.h new file mode 100644 index 0000000..d01bb33 --- /dev/null +++ b/chrome/browser/extensions/extension_management_internal.h @@ -0,0 +1,87 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGEMENT_INTERNAL_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGEMENT_INTERNAL_H_ + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "chrome/browser/extensions/extension_management.h" +#include "extensions/common/manifest.h" + +namespace base { +class DictionaryValue; +} // namespace base + +namespace extensions { + +class URLPatternSet; + +namespace internal { + +// Class to hold extension management settings for one or a group of +// extensions. Settings can be applied to an individual extension identified +// by an ID, a group of extensions with specific |update_url| or all +// extensions at once. +struct IndividualSettings { + enum ParsingScope { + // Parses the default settings. + SCOPE_DEFAULT = 0, + // Parses the settings for an extension with specified extension ID. + SCOPE_INDIVIDUAL, + }; + + IndividualSettings(); + ~IndividualSettings(); + + void Reset(); + + // Parses the individual settings. |dict| is the a sub-dictionary in extension + // management preference and |scope| represents the applicable range of the + // settings, a single extension, a group of extensions or default settings. + // Note that in case of parsing errors, |this| will NOT be left untouched. + bool Parse(const base::DictionaryValue* dict, ParsingScope scope); + + // Extension installation mode. Setting this to INSTALLATION_FORCED or + // INSTALLATION_RECOMMENDED will enable extension auto-loading (only + // applicable to single extension), and in this case the |update_url| must + // be specified, containing the update URL for this extension. + // Note that |update_url| will be ignored for INSTALLATION_ALLOWED and + // INSTALLATION_BLOCKED installation mode. + // These settings will override the default settings, and unspecified + // settings will take value from default settings. + ExtensionManagement::InstallationMode installation_mode; + std::string update_url; + + private: + DISALLOW_ASSIGN(IndividualSettings); +}; + +// Global extension management settings, applicable to all extensions. +struct GlobalSettings { + GlobalSettings(); + ~GlobalSettings(); + + void Reset(); + + // Settings specifying which URLs are allowed to install extensions, will be + // enforced only if |has_restricted_install_sources| is set to true. + URLPatternSet install_sources; + bool has_restricted_install_sources; + + // Settings specifying all allowed app/extension types, will be enforced + // only of |has_restricted_allowed_types| is set to true. + std::vector<Manifest::Type> allowed_types; + bool has_restricted_allowed_types; + + private: + DISALLOW_COPY_AND_ASSIGN(GlobalSettings); +}; + +} // namespace internal + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_MANAGEMENT_INTERNAL_H_ diff --git a/chrome/browser/extensions/extension_management_unittest.cc b/chrome/browser/extensions/extension_management_unittest.cc index 9d91895..35f12f5 100644 --- a/chrome/browser/extensions/extension_management_unittest.cc +++ b/chrome/browser/extensions/extension_management_unittest.cc @@ -11,6 +11,7 @@ #include "base/prefs/testing_pref_service.h" #include "base/values.h" #include "chrome/browser/extensions/extension_management.h" +#include "chrome/browser/extensions/extension_management_internal.h" #include "chrome/browser/extensions/extension_management_test_util.h" #include "chrome/browser/extensions/external_policy_loader.h" #include "extensions/browser/pref_names.h" @@ -93,6 +94,14 @@ class ExtensionManagementServiceTest : public testing::Test { pref_service_->RemoveUserPref(path); } + const internal::IndividualSettings* ReadById(const ExtensionId& id) { + return extension_management_->ReadById(id); + } + + const internal::GlobalSettings* ReadGlobalSettings() { + return extension_management_->ReadGlobalSettings(); + } + void SetExampleDictPref() { std::string error_msg; scoped_ptr<base::Value> parsed(base::JSONReader::ReadAndReturnError( @@ -202,10 +211,8 @@ TEST_F(ExtensionManagementServiceTest, LegacyInstallSources) { allowed_sites_pref.AppendString("https://corp.mycompany.com/*"); SetPref( true, pref_names::kAllowedInstallSites, allowed_sites_pref.DeepCopy()); - const URLPatternSet& allowed_sites = - extension_management_->ReadGlobalSettings().install_sources; - ASSERT_TRUE(extension_management_->ReadGlobalSettings() - .has_restricted_install_sources); + const URLPatternSet& allowed_sites = ReadGlobalSettings()->install_sources; + ASSERT_TRUE(ReadGlobalSettings()->has_restricted_install_sources); EXPECT_FALSE(allowed_sites.is_empty()); EXPECT_TRUE(allowed_sites.MatchesURL(GURL("https://www.example.com/foo"))); EXPECT_FALSE(allowed_sites.MatchesURL(GURL("https://www.example.com/bar"))); @@ -224,9 +231,8 @@ TEST_F(ExtensionManagementServiceTest, LegacyAllowedTypes) { SetPref(true, pref_names::kAllowedTypes, allowed_types_pref.DeepCopy()); const std::vector<Manifest::Type>& allowed_types = - extension_management_->ReadGlobalSettings().allowed_types; - ASSERT_TRUE( - extension_management_->ReadGlobalSettings().has_restricted_allowed_types); + ReadGlobalSettings()->allowed_types; + ASSERT_TRUE(ReadGlobalSettings()->has_restricted_allowed_types); EXPECT_TRUE(allowed_types.size() == 2); EXPECT_FALSE(std::find(allowed_types.begin(), allowed_types.end(), @@ -246,9 +252,9 @@ TEST_F(ExtensionManagementServiceTest, LegacyInstallBlacklist) { denied_list_pref.AppendString(kTargetExtension); SetPref(true, pref_names::kInstallDenyList, denied_list_pref.DeepCopy()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); } @@ -262,15 +268,15 @@ TEST_F(ExtensionManagementServiceTest, LegacyInstallWhitelist) { SetPref(true, pref_names::kInstallDenyList, denied_list_pref.DeepCopy()); SetPref(true, pref_names::kInstallAllowList, allowed_list_pref.DeepCopy()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); // Verify that install whitelist preference set by user is ignored. RemovePref(true, pref_names::kInstallAllowList); SetPref(false, pref_names::kInstallAllowList, allowed_list_pref.DeepCopy()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); } @@ -282,17 +288,16 @@ TEST_F(ExtensionManagementServiceTest, LegacyInstallForcelist) { &forced_list_pref, kTargetExtension, kExampleUpdateUrl); SetPref(true, pref_names::kInstallForceList, forced_list_pref.DeepCopy()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_FORCED); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).update_url, - kExampleUpdateUrl); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->update_url, kExampleUpdateUrl); + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); // Verify that install forcelist preference set by user is ignored. RemovePref(true, pref_names::kInstallForceList); SetPref(false, pref_names::kInstallForceList, forced_list_pref.DeepCopy()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); } @@ -302,34 +307,27 @@ TEST_F(ExtensionManagementServiceTest, PreferenceParsing) { // Verifies the installation mode settings. EXPECT_TRUE(extension_management_->BlacklistedByDefault()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); - EXPECT_EQ( - extension_management_->ReadById(kTargetExtension2).installation_mode, - ExtensionManagement::INSTALLATION_FORCED); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension2).update_url, - kExampleUpdateUrl); - EXPECT_EQ( - extension_management_->ReadById(kTargetExtension3).installation_mode, - ExtensionManagement::INSTALLATION_RECOMMENDED); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension3).update_url, - kExampleUpdateUrl); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension2)->installation_mode, + ExtensionManagement::INSTALLATION_FORCED); + EXPECT_EQ(ReadById(kTargetExtension2)->update_url, kExampleUpdateUrl); + EXPECT_EQ(ReadById(kTargetExtension3)->installation_mode, + ExtensionManagement::INSTALLATION_RECOMMENDED); + EXPECT_EQ(ReadById(kTargetExtension3)->update_url, kExampleUpdateUrl); + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); // Verifies global settings. - EXPECT_TRUE(extension_management_->ReadGlobalSettings() - .has_restricted_install_sources); - const URLPatternSet& allowed_sites = - extension_management_->ReadGlobalSettings().install_sources; + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_install_sources); + const URLPatternSet& allowed_sites = ReadGlobalSettings()->install_sources; EXPECT_EQ(allowed_sites.size(), 1u); EXPECT_TRUE(allowed_sites.MatchesURL(GURL("http://foo.com/entry"))); EXPECT_FALSE(allowed_sites.MatchesURL(GURL("http://bar.com/entry"))); - EXPECT_TRUE( - extension_management_->ReadGlobalSettings().has_restricted_allowed_types); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_allowed_types); const std::vector<Manifest::Type>& allowed_types = - extension_management_->ReadGlobalSettings().allowed_types; + ReadGlobalSettings()->allowed_types; EXPECT_EQ(allowed_types.size(), 2u); EXPECT_TRUE(std::find(allowed_types.begin(), allowed_types.end(), @@ -347,11 +345,9 @@ TEST_F(ExtensionManagementServiceTest, NewInstallSources) { allowed_sites_pref.AppendString("https://www.example.com/foo"); SetPref( true, pref_names::kAllowedInstallSites, allowed_sites_pref.DeepCopy()); - EXPECT_TRUE(extension_management_->ReadGlobalSettings() - .has_restricted_install_sources); - EXPECT_TRUE( - extension_management_->ReadGlobalSettings() - .install_sources.MatchesURL(GURL("https://www.example.com/foo"))); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_install_sources); + EXPECT_TRUE(ReadGlobalSettings()->install_sources.MatchesURL( + GURL("https://www.example.com/foo"))); // Set the new dictionary preference. { @@ -359,22 +355,18 @@ TEST_F(ExtensionManagementServiceTest, NewInstallSources) { updater.ClearInstallSources(); } // Verifies that the new one overrides the legacy ones. - EXPECT_TRUE(extension_management_->ReadGlobalSettings() - .has_restricted_install_sources); - EXPECT_FALSE( - extension_management_->ReadGlobalSettings() - .install_sources.MatchesURL(GURL("https://www.example.com/foo"))); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_install_sources); + EXPECT_FALSE(ReadGlobalSettings()->install_sources.MatchesURL( + GURL("https://www.example.com/foo"))); // Updates the new dictionary preference. { PrefUpdater updater(pref_service_.get()); updater.AddInstallSource("https://corp.mycompany.com/*"); } - EXPECT_TRUE(extension_management_->ReadGlobalSettings() - .has_restricted_install_sources); - EXPECT_TRUE(extension_management_->ReadGlobalSettings() - .install_sources.MatchesURL( - GURL("https://corp.mycompany.com/entry"))); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_install_sources); + EXPECT_TRUE(ReadGlobalSettings()->install_sources.MatchesURL( + GURL("https://corp.mycompany.com/entry"))); } // Tests functionality of new preference as to deprecate legacy @@ -384,12 +376,9 @@ TEST_F(ExtensionManagementServiceTest, NewAllowedTypes) { base::ListValue allowed_types_pref; allowed_types_pref.AppendInteger(Manifest::TYPE_USER_SCRIPT); SetPref(true, pref_names::kAllowedTypes, allowed_types_pref.DeepCopy()); - EXPECT_TRUE( - extension_management_->ReadGlobalSettings().has_restricted_allowed_types); - EXPECT_EQ(extension_management_->ReadGlobalSettings().allowed_types.size(), - 1u); - EXPECT_EQ(extension_management_->ReadGlobalSettings().allowed_types[0], - Manifest::TYPE_USER_SCRIPT); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_allowed_types); + EXPECT_EQ(ReadGlobalSettings()->allowed_types.size(), 1u); + EXPECT_EQ(ReadGlobalSettings()->allowed_types[0], Manifest::TYPE_USER_SCRIPT); // Set the new dictionary preference. { @@ -397,22 +386,17 @@ TEST_F(ExtensionManagementServiceTest, NewAllowedTypes) { updater.ClearAllowedTypes(); } // Verifies that the new one overrides the legacy ones. - EXPECT_TRUE( - extension_management_->ReadGlobalSettings().has_restricted_allowed_types); - EXPECT_EQ(extension_management_->ReadGlobalSettings().allowed_types.size(), - 0u); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_allowed_types); + EXPECT_EQ(ReadGlobalSettings()->allowed_types.size(), 0u); // Updates the new dictionary preference. { PrefUpdater updater(pref_service_.get()); updater.AddAllowedType("theme"); } - EXPECT_TRUE( - extension_management_->ReadGlobalSettings().has_restricted_allowed_types); - EXPECT_EQ(extension_management_->ReadGlobalSettings().allowed_types.size(), - 1u); - EXPECT_EQ(extension_management_->ReadGlobalSettings().allowed_types[0], - Manifest::TYPE_THEME); + EXPECT_TRUE(ReadGlobalSettings()->has_restricted_allowed_types); + EXPECT_EQ(ReadGlobalSettings()->allowed_types.size(), 1u); + EXPECT_EQ(ReadGlobalSettings()->allowed_types[0], Manifest::TYPE_THEME); } // Tests functionality of new preference as to deprecate legacy @@ -427,9 +411,9 @@ TEST_F(ExtensionManagementServiceTest, NewInstallBlacklist) { updater.ClearPerExtensionSettings(kOtherExtension); } EXPECT_FALSE(extension_management_->BlacklistedByDefault()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); // Set legacy preference. @@ -444,12 +428,11 @@ TEST_F(ExtensionManagementServiceTest, NewInstallBlacklist) { // Verifies that the new one have higher priority over the legacy ones. EXPECT_FALSE(extension_management_->BlacklistedByDefault()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, + ExtensionManagement::INSTALLATION_BLOCKED); + EXPECT_EQ(ReadById(kTargetExtension2)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); - EXPECT_EQ( - extension_management_->ReadById(kTargetExtension2).installation_mode, - ExtensionManagement::INSTALLATION_BLOCKED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); } @@ -465,9 +448,9 @@ TEST_F(ExtensionManagementServiceTest, NewInstallWhitelist) { updater.ClearPerExtensionSettings(kOtherExtension); } EXPECT_TRUE(extension_management_->BlacklistedByDefault()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); // Set legacy preference. @@ -481,12 +464,11 @@ TEST_F(ExtensionManagementServiceTest, NewInstallWhitelist) { // Verifies that the new one have higher priority over the legacy ones. EXPECT_TRUE(extension_management_->BlacklistedByDefault()); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, + ExtensionManagement::INSTALLATION_ALLOWED); + EXPECT_EQ(ReadById(kTargetExtension2)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); - EXPECT_EQ( - extension_management_->ReadById(kTargetExtension2).installation_mode, - ExtensionManagement::INSTALLATION_ALLOWED); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_BLOCKED); } @@ -506,11 +488,10 @@ TEST_F(ExtensionManagementServiceTest, NewInstallForcelist) { kTargetExtension, kExampleUpdateUrl, true); updater.ClearPerExtensionSettings(kOtherExtension); } - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->installation_mode, ExtensionManagement::INSTALLATION_FORCED); - EXPECT_EQ(extension_management_->ReadById(kTargetExtension).update_url, - kExampleUpdateUrl); - EXPECT_EQ(extension_management_->ReadById(kOtherExtension).installation_mode, + EXPECT_EQ(ReadById(kTargetExtension)->update_url, kExampleUpdateUrl); + EXPECT_EQ(ReadById(kOtherExtension)->installation_mode, ExtensionManagement::INSTALLATION_ALLOWED); } diff --git a/chrome/browser/extensions/standard_management_policy_provider.cc b/chrome/browser/extensions/standard_management_policy_provider.cc index f282406..0212257 100644 --- a/chrome/browser/extensions/standard_management_policy_provider.cc +++ b/chrome/browser/extensions/standard_management_policy_provider.cc @@ -4,7 +4,6 @@ #include "chrome/browser/extensions/standard_management_policy_provider.h" -#include <algorithm> #include <string> #include "base/logging.h" @@ -77,16 +76,12 @@ bool StandardManagementPolicyProvider::UserMayLoad( if (Manifest::IsComponentLocation(extension->location())) return true; - // Fields in |by_id| will automatically fall back to default settings if - // they are not specified by policy. - const ExtensionManagement::IndividualSettings& by_id = - settings_->ReadById(extension->id()); - const ExtensionManagement::GlobalSettings& global = - settings_->ReadGlobalSettings(); + ExtensionManagement::InstallationMode installation_mode = + settings_->GetInstallationMode(extension->id()); // Force-installed extensions cannot be overwritten manually. if (!Manifest::IsPolicyLocation(extension->location()) && - by_id.installation_mode == ExtensionManagement::INSTALLATION_FORCED) { + installation_mode == ExtensionManagement::INSTALLATION_FORCED) { return ReturnLoadError(extension, error); } @@ -107,19 +102,15 @@ bool StandardManagementPolicyProvider::UserMayLoad( case Manifest::TYPE_LEGACY_PACKAGED_APP: case Manifest::TYPE_PLATFORM_APP: case Manifest::TYPE_SHARED_MODULE: { - if (global.has_restricted_allowed_types && - std::find(global.allowed_types.begin(), - global.allowed_types.end(), - extension->GetType()) == global.allowed_types.end()) { + if (!settings_->IsAllowedManifestType(extension->GetType())) return ReturnLoadError(extension, error); - } break; } case Manifest::NUM_LOAD_TYPES: NOTREACHED(); } - if (by_id.installation_mode == ExtensionManagement::INSTALLATION_BLOCKED) + if (installation_mode == ExtensionManagement::INSTALLATION_BLOCKED) return ReturnLoadError(extension, error); return true; diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index a40a726..25b5a99 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -622,6 +622,8 @@ 'browser/extensions/extension_management.h', 'browser/extensions/extension_management_constants.cc', 'browser/extensions/extension_management_constants.h', + 'browser/extensions/extension_management_internal.cc', + 'browser/extensions/extension_management_internal.h', 'browser/extensions/extension_message_bubble_controller.cc', 'browser/extensions/extension_message_bubble_controller.h', 'browser/extensions/extension_renderer_state.cc', |