diff options
author | binjin <binjin@chromium.org> | 2014-10-02 04:47:12 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-10-02 11:47:29 +0000 |
commit | 81d7c55c47677582259ab1b62b92d0d7c2557d47 (patch) | |
tree | b7717a55f3e23ada91a355dc53c5a850fd2fcd8c /chrome/browser/extensions | |
parent | 9accc09a59b1b5e6a2b40d8dace0a47e16ba4a12 (diff) | |
download | chromium_src-81d7c55c47677582259ab1b62b92d0d7c2557d47.zip chromium_src-81d7c55c47677582259ab1b62b92d0d7c2557d47.tar.gz chromium_src-81d7c55c47677582259ab1b62b92d0d7c2557d47.tar.bz2 |
Refactor ExtensionManagement
This CL removes IndividualSettings and GlobalSettings from ExtensionManagment header file in order to simply header file and reduce static size of ExtensionManagement class. Linked pointer is used to prevent potential unintended use of copy constructor of these structure in the future, when more fields are added.
A new internal header file is created since these structures are also used in unit tests.
BUG=177351
Review URL: https://codereview.chromium.org/602803002
Cr-Commit-Position: refs/heads/master@{#297808}
Diffstat (limited to 'chrome/browser/extensions')
6 files changed, 356 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; |