Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_management.cc
index 423e655..5aeb542 100644 (file)
@@ -4,14 +4,19 @@
 
 #include "chrome/browser/extensions/extension_management.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/string16.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/permissions_based_management_policy_provider.h"
 #include "chrome/browser/extensions/standard_management_policy_provider.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "extensions/browser/pref_names.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/url_pattern.h"
 #include "url/gurl.h"
 
 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,13 +48,22 @@ 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));
+  providers_.push_back(new StandardManagementPolicyProvider(this));
+  providers_.push_back(new PermissionsBasedManagementPolicyProvider(this));
 }
 
 ExtensionManagement::~ExtensionManagement() {
 }
 
+void ExtensionManagement::Shutdown() {
+  pref_change_registrar_.RemoveAll();
+  pref_service_ = nullptr;
+}
+
 void ExtensionManagement::AddObserver(Observer* observer) {
   observer_list_.AddObserver(observer);
 }
@@ -146,26 +72,59 @@ void ExtensionManagement::RemoveObserver(Observer* observer) {
   observer_list_.RemoveObserver(observer);
 }
 
-ManagementPolicy::Provider* ExtensionManagement::GetProvider() {
-  return provider_.get();
+std::vector<ManagementPolicy::Provider*> ExtensionManagement::GetProviders()
+    const {
+  return providers_.get();
+}
+
+bool ExtensionManagement::BlacklistedByDefault() const {
+  return default_settings_->installation_mode == INSTALLATION_BLOCKED;
 }
 
-bool ExtensionManagement::BlacklistedByDefault() {
-  return default_settings_.installation_mode == INSTALLATION_BLOCKED;
+ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
+    const Extension* extension) const {
+  // Check per-extension installation mode setting first.
+  auto iter_id = settings_by_id_.find(extension->id());
+  if (iter_id != settings_by_id_.end())
+    return iter_id->second->installation_mode;
+  std::string update_url;
+  // Check per-update-url installation mode setting.
+  if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
+                                       &update_url)) {
+    auto iter_update_url = settings_by_update_url_.find(update_url);
+    if (iter_update_url != settings_by_update_url_.end())
+      return iter_update_url->second->installation_mode;
+  }
+  // Fall back to default installation mode setting.
+  return default_settings_->installation_mode;
 }
 
 scoped_ptr<base::DictionaryValue> ExtensionManagement::GetForceInstallList()
     const {
-  scoped_ptr<base::DictionaryValue> forcelist(new base::DictionaryValue());
+  scoped_ptr<base::DictionaryValue> install_list(new base::DictionaryValue());
   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);
+          install_list.get(), it->first, it->second->update_url);
     }
   }
-  return forcelist.Pass();
+  return install_list.Pass();
+}
+
+scoped_ptr<base::DictionaryValue>
+ExtensionManagement::GetRecommendedInstallList() const {
+  scoped_ptr<base::DictionaryValue> install_list(new base::DictionaryValue());
+  for (SettingsIdMap::const_iterator it = settings_by_id_.begin();
+       it != settings_by_id_.end();
+       ++it) {
+    if (it->second->installation_mode == INSTALLATION_RECOMMENDED) {
+      ExternalPolicyLoader::AddExtension(
+          install_list.get(), it->first, it->second->update_url);
+    }
+  }
+  return install_list.Pass();
 }
 
 bool ExtensionManagement::IsInstallationExplicitlyAllowed(
@@ -176,19 +135,19 @@ bool ExtensionManagement::IsInstallationExplicitlyAllowed(
     return false;
   // Checks if the extension is on the automatically installed list or
   // install white-list.
-  InstallationMode mode = it->second.installation_mode;
+  InstallationMode mode = it->second->installation_mode;
   return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
          mode == INSTALLATION_ALLOWED;
 }
 
-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;
@@ -198,18 +157,64 @@ 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_;
+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();
+}
+
+APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
+    const Extension* extension) const {
+  // Fetch per-extension blocked permissions setting.
+  auto iter_id = settings_by_id_.find(extension->id());
+
+  // Fetch per-update-url blocked permissions setting.
+  std::string update_url;
+  auto iter_update_url = settings_by_update_url_.end();
+  if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
+                                       &update_url)) {
+    iter_update_url = settings_by_update_url_.find(update_url);
+  }
+
+  if (iter_id != settings_by_id_.end() &&
+      iter_update_url != settings_by_update_url_.end()) {
+    // Blocked permissions setting are specified in both per-extension and
+    // per-update-url settings, try to merge them.
+    APIPermissionSet merged;
+    APIPermissionSet::Union(iter_id->second->blocked_permissions,
+                            iter_update_url->second->blocked_permissions,
+                            &merged);
+    return merged;
+  }
+  // Check whether if in one of them, setting is specified.
+  if (iter_id != settings_by_id_.end())
+    return iter_id->second->blocked_permissions;
+  if (iter_update_url != settings_by_update_url_.end())
+    return iter_update_url->second->blocked_permissions;
+  // Fall back to the default blocked permissions setting.
+  return default_settings_->blocked_permissions;
+}
+
+scoped_refptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
+    const Extension* extension) const {
+  // Only api permissions are supported currently.
+  return scoped_refptr<const PermissionSet>(new PermissionSet(
+      GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
+      URLPatternSet(), URLPatternSet()));
 }
 
-const ExtensionManagement::GlobalSettings&
-ExtensionManagement::ReadGlobalSettings() const {
-  return global_settings_;
+bool ExtensionManagement::IsPermissionSetAllowed(
+    const Extension* extension,
+    scoped_refptr<const PermissionSet> perms) const {
+  for (const auto& blocked_api : GetBlockedAPIPermissions(extension)) {
+    if (perms->HasAPIPermission(blocked_api->id()))
+      return false;
+  }
+  return true;
 }
 
 void ExtensionManagement::Refresh() {
@@ -238,23 +243,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.
@@ -294,7 +300,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;
       }
@@ -302,14 +308,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 << ": "
@@ -320,20 +326,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);
       }
     }
   }
@@ -344,22 +350,37 @@ 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;
-        continue;
-      }
-      IndividualSettings* by_id = AccessById(extension_id);
-      if (!ParseIndividualSettings(subdict, SCOPE_INDIVIDUAL, by_id)) {
-        settings_by_id_.erase(settings_by_id_.find(extension_id));
-        LOG(WARNING) << "Malformed Extension Management settings for "
-                     << extension_id << ".";
+      if (StartsWithASCII(iter.key(), schema_constants::kUpdateUrlPrefix,
+                          true)) {
+        const std::string& update_url =
+            iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
+        if (!GURL(update_url).is_valid()) {
+          LOG(WARNING) << "Invalid update URL: " << update_url << ".";
+          continue;
+        }
+        internal::IndividualSettings* by_update_url =
+            AccessByUpdateUrl(update_url);
+        if (!by_update_url->Parse(
+                subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
+          settings_by_update_url_.erase(update_url);
+          LOG(WARNING) << "Malformed Extension Management settings for "
+                          "extensions with update url: " << update_url << ".";
+        }
+      } else {
+        const std::string& extension_id = iter.key();
+        if (!crx_file::id_util::IdIsValid(extension_id)) {
+          LOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
+          continue;
+        }
+        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 << ".";
+        }
       }
     }
   }
@@ -369,6 +390,8 @@ const base::Value* ExtensionManagement::LoadPreference(
     const char* pref_name,
     bool force_managed,
     base::Value::Type expected_type) {
+  if (!pref_service_)
+    return nullptr;
   const PrefService::Preference* pref =
       pref_service_->FindPreference(pref_name);
   if (pref && !pref->IsDefaultValue() &&
@@ -377,7 +400,7 @@ const base::Value* ExtensionManagement::LoadPreference(
     if (value && value->IsType(expected_type))
       return value;
   }
-  return NULL;
+  return nullptr;
 }
 
 void ExtensionManagement::OnExtensionPrefChanged() {
@@ -390,13 +413,28 @@ void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
       Observer, observer_list_, OnExtensionManagementSettingsChanged());
 }
 
-ExtensionManagement::IndividualSettings* ExtensionManagement::AccessById(
+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;
+}
+
+internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
+    const std::string& update_url) {
+  DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
+  SettingsUpdateUrlMap::iterator it = settings_by_update_url_.find(update_url);
+  if (it == settings_by_update_url_.end()) {
+    scoped_ptr<internal::IndividualSettings> settings(
+        new internal::IndividualSettings(*default_settings_));
+    it = settings_by_update_url_.add(update_url, settings.Pass()).first;
+  }
+  return it->second;
 }
 
 ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(