blob: f593d7f0385979ffe5edebb006b3ad0e655df71c [file] [log] [blame]
binjin5f405ef2014-09-03 21:23:161// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_management.h"
6
dcheng1fc00f12015-12-26 22:18:037#include <utility>
binjin81d7c552014-10-02 11:47:128
binjin1569c9b2014-09-05 13:33:189#include "base/bind.h"
10#include "base/bind_helpers.h"
binjin5f405ef2014-09-03 21:23:1611#include "base/logging.h"
lazyboy4aeef202016-09-07 21:28:5912#include "base/memory/ptr_util.h"
rkaplowdd66a1342015-03-05 00:31:4913#include "base/metrics/histogram_macros.h"
tripta.g0ac673a2017-07-07 05:45:0914#include "base/stl_util.h"
binjine6b58b52014-10-31 01:55:5715#include "base/strings/string16.h"
binjinb2454382014-09-22 15:17:4316#include "base/strings/string_util.h"
rkaplowdd66a1342015-03-05 00:31:4917#include "base/trace_event/trace_event.h"
binjin8e3d0182014-12-04 16:44:2818#include "base/version.h"
binjinb2454382014-09-22 15:17:4319#include "chrome/browser/extensions/extension_management_constants.h"
binjin81d7c552014-10-02 11:47:1220#include "chrome/browser/extensions/extension_management_internal.h"
binjin30301062014-09-08 20:27:3421#include "chrome/browser/extensions/external_policy_loader.h"
binjin5f405ef2014-09-03 21:23:1622#include "chrome/browser/extensions/external_provider_impl.h"
binjine6b58b52014-10-31 01:55:5723#include "chrome/browser/extensions/permissions_based_management_policy_provider.h"
binjin1569c9b2014-09-05 13:33:1824#include "chrome/browser/extensions/standard_management_policy_provider.h"
binjin9733df12014-09-08 15:21:2125#include "chrome/browser/profiles/incognito_helpers.h"
binjin1569c9b2014-09-05 13:33:1826#include "chrome/browser/profiles/profile.h"
binjin5f405ef2014-09-03 21:23:1627#include "components/crx_file/id_util.h"
binjin1569c9b2014-09-05 13:33:1828#include "components/keyed_service/content/browser_context_dependency_manager.h"
binjinb2454382014-09-22 15:17:4329#include "components/pref_registry/pref_registry_syncable.h"
brettwb1fc1b82016-02-02 00:19:0830#include "components/prefs/pref_service.h"
binjin5f405ef2014-09-03 21:23:1631#include "extensions/browser/pref_names.h"
rdevlin.cronin0670b562016-07-02 02:05:4332#include "extensions/common/extension.h"
binjin685ade82014-11-06 09:53:5633#include "extensions/common/manifest_constants.h"
binjine6b58b52014-10-31 01:55:5734#include "extensions/common/permissions/api_permission_set.h"
35#include "extensions/common/permissions/permission_set.h"
binjin5f405ef2014-09-03 21:23:1636#include "extensions/common/url_pattern.h"
binjin311ecdf2014-09-12 22:56:5237#include "url/gurl.h"
binjin5f405ef2014-09-03 21:23:1638
achuith4607f072017-03-08 11:49:1339#if defined(OS_CHROMEOS)
40#include "chrome/browser/chromeos/profiles/profile_helper.h"
41#endif
42
binjin5f405ef2014-09-03 21:23:1643namespace extensions {
44
achuith4607f072017-03-08 11:49:1345ExtensionManagement::ExtensionManagement(PrefService* pref_service,
46 bool is_signin_profile)
47 : pref_service_(pref_service), is_signin_profile_(is_signin_profile) {
rkaplowdd66a1342015-03-05 00:31:4948 TRACE_EVENT0("browser,startup",
49 "ExtensionManagement::ExtensionManagement::ctor");
binjin1569c9b2014-09-05 13:33:1850 pref_change_registrar_.Init(pref_service_);
51 base::Closure pref_change_callback = base::Bind(
52 &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this));
53 pref_change_registrar_.Add(pref_names::kInstallAllowList,
54 pref_change_callback);
55 pref_change_registrar_.Add(pref_names::kInstallDenyList,
56 pref_change_callback);
57 pref_change_registrar_.Add(pref_names::kInstallForceList,
58 pref_change_callback);
achuith4607f072017-03-08 11:49:1359 pref_change_registrar_.Add(pref_names::kInstallLoginScreenAppList,
60 pref_change_callback);
binjin1569c9b2014-09-05 13:33:1861 pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
62 pref_change_callback);
63 pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
binjinb2454382014-09-22 15:17:4364 pref_change_registrar_.Add(pref_names::kExtensionManagement,
65 pref_change_callback);
binjin81d7c552014-10-02 11:47:1266 // Note that both |global_settings_| and |default_settings_| will be null
67 // before first call to Refresh(), so in order to resolve this, Refresh() must
68 // be called in the initialization of ExtensionManagement.
binjin1569c9b2014-09-05 13:33:1869 Refresh();
lazyboy4aeef202016-09-07 21:28:5970 providers_.push_back(
71 base::MakeUnique<StandardManagementPolicyProvider>(this));
72 providers_.push_back(
73 base::MakeUnique<PermissionsBasedManagementPolicyProvider>(this));
binjin5f405ef2014-09-03 21:23:1674}
75
76ExtensionManagement::~ExtensionManagement() {
77}
78
binjine6b58b52014-10-31 01:55:5779void ExtensionManagement::Shutdown() {
80 pref_change_registrar_.RemoveAll();
81 pref_service_ = nullptr;
82}
83
binjin1569c9b2014-09-05 13:33:1884void ExtensionManagement::AddObserver(Observer* observer) {
85 observer_list_.AddObserver(observer);
86}
87
88void ExtensionManagement::RemoveObserver(Observer* observer) {
89 observer_list_.RemoveObserver(observer);
90}
91
lazyboy4aeef202016-09-07 21:28:5992const std::vector<std::unique_ptr<ManagementPolicy::Provider>>&
93ExtensionManagement::GetProviders() const {
94 return providers_;
binjin1569c9b2014-09-05 13:33:1895}
96
binjin81d7c552014-10-02 11:47:1297bool ExtensionManagement::BlacklistedByDefault() const {
98 return default_settings_->installation_mode == INSTALLATION_BLOCKED;
99}
100
101ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
binjin685ade82014-11-06 09:53:56102 const Extension* extension) const {
103 // Check per-extension installation mode setting first.
104 auto iter_id = settings_by_id_.find(extension->id());
105 if (iter_id != settings_by_id_.end())
106 return iter_id->second->installation_mode;
107 std::string update_url;
108 // Check per-update-url installation mode setting.
109 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
110 &update_url)) {
111 auto iter_update_url = settings_by_update_url_.find(update_url);
112 if (iter_update_url != settings_by_update_url_.end())
113 return iter_update_url->second->installation_mode;
114 }
115 // Fall back to default installation mode setting.
116 return default_settings_->installation_mode;
binjin1569c9b2014-09-05 13:33:18117}
118
dchengc963c7142016-04-08 03:55:22119std::unique_ptr<base::DictionaryValue>
hashimoto146e05a2016-11-18 07:42:53120ExtensionManagement::GetForceInstallList() const {
achuith4607f072017-03-08 11:49:13121 return GetInstallListByMode(INSTALLATION_FORCED);
binjincccacef2014-10-13 19:00:20122}
123
dchengc963c7142016-04-08 03:55:22124std::unique_ptr<base::DictionaryValue>
binjincccacef2014-10-13 19:00:20125ExtensionManagement::GetRecommendedInstallList() const {
achuith4607f072017-03-08 11:49:13126 return GetInstallListByMode(INSTALLATION_RECOMMENDED);
binjin30301062014-09-08 20:27:34127}
128
binjinc641add2014-10-15 16:20:45129bool ExtensionManagement::IsInstallationExplicitlyAllowed(
130 const ExtensionId& id) const {
avi3ec9c0d2016-12-27 22:38:06131 auto it = settings_by_id_.find(id);
binjinc641add2014-10-15 16:20:45132 // No settings explicitly specified for |id|.
133 if (it == settings_by_id_.end())
134 return false;
135 // Checks if the extension is on the automatically installed list or
136 // install white-list.
137 InstallationMode mode = it->second->installation_mode;
138 return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
139 mode == INSTALLATION_ALLOWED;
binjin30301062014-09-08 20:27:34140}
141
binjin81d7c552014-10-02 11:47:12142bool ExtensionManagement::IsOffstoreInstallAllowed(
143 const GURL& url,
144 const GURL& referrer_url) const {
binjin311ecdf2014-09-12 22:56:52145 // No allowed install sites specified, disallow by default.
binjin81d7c552014-10-02 11:47:12146 if (!global_settings_->has_restricted_install_sources)
binjin311ecdf2014-09-12 22:56:52147 return false;
148
binjin81d7c552014-10-02 11:47:12149 const URLPatternSet& url_patterns = global_settings_->install_sources;
binjin311ecdf2014-09-12 22:56:52150
151 if (!url_patterns.MatchesURL(url))
152 return false;
153
154 // The referrer URL must also be whitelisted, unless the URL has the file
155 // scheme (there's no referrer for those URLs).
156 return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url);
157}
158
binjin81d7c552014-10-02 11:47:12159bool ExtensionManagement::IsAllowedManifestType(
160 Manifest::Type manifest_type) const {
161 if (!global_settings_->has_restricted_allowed_types)
162 return true;
163 const std::vector<Manifest::Type>& allowed_types =
164 global_settings_->allowed_types;
tripta.g0ac673a2017-07-07 05:45:09165 return base::ContainsValue(allowed_types, manifest_type);
binjin1569c9b2014-09-05 13:33:18166}
167
binjin685ade82014-11-06 09:53:56168APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
169 const Extension* extension) const {
170 // Fetch per-extension blocked permissions setting.
171 auto iter_id = settings_by_id_.find(extension->id());
172
173 // Fetch per-update-url blocked permissions setting.
174 std::string update_url;
175 auto iter_update_url = settings_by_update_url_.end();
176 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
177 &update_url)) {
178 iter_update_url = settings_by_update_url_.find(update_url);
179 }
180
181 if (iter_id != settings_by_id_.end() &&
182 iter_update_url != settings_by_update_url_.end()) {
183 // Blocked permissions setting are specified in both per-extension and
184 // per-update-url settings, try to merge them.
185 APIPermissionSet merged;
186 APIPermissionSet::Union(iter_id->second->blocked_permissions,
187 iter_update_url->second->blocked_permissions,
188 &merged);
189 return merged;
190 }
191 // Check whether if in one of them, setting is specified.
192 if (iter_id != settings_by_id_.end())
193 return iter_id->second->blocked_permissions;
194 if (iter_update_url != settings_by_update_url_.end())
195 return iter_update_url->second->blocked_permissions;
196 // Fall back to the default blocked permissions setting.
197 return default_settings_->blocked_permissions;
binjine6b58b52014-10-31 01:55:57198}
199
nrpetere33d2a5b2017-04-25 00:12:31200const URLPatternSet& ExtensionManagement::GetDefaultRuntimeBlockedHosts()
201 const {
202 return default_settings_->runtime_blocked_hosts;
203}
204
205const URLPatternSet& ExtensionManagement::GetDefaultRuntimeAllowedHosts()
206 const {
207 return default_settings_->runtime_allowed_hosts;
208}
209
nrpeter40e16382017-04-13 17:34:58210const URLPatternSet& ExtensionManagement::GetRuntimeBlockedHosts(
211 const Extension* extension) const {
212 auto iter_id = settings_by_id_.find(extension->id());
213 if (iter_id != settings_by_id_.end())
214 return iter_id->second->runtime_blocked_hosts;
215 return default_settings_->runtime_blocked_hosts;
216}
217
218const URLPatternSet& ExtensionManagement::GetRuntimeAllowedHosts(
219 const Extension* extension) const {
220 auto iter_id = settings_by_id_.find(extension->id());
221 if (iter_id != settings_by_id_.end())
222 return iter_id->second->runtime_allowed_hosts;
223 return default_settings_->runtime_allowed_hosts;
224}
225
nrpetere33d2a5b2017-04-25 00:12:31226bool ExtensionManagement::UsesDefaultRuntimeHostRestrictions(
227 const Extension* extension) const {
228 return settings_by_id_.find(extension->id()) == settings_by_id_.end();
229}
230
231bool ExtensionManagement::IsRuntimeBlockedHost(const Extension* extension,
232 const GURL& url) const {
nrpeter40e16382017-04-13 17:34:58233 auto iter_id = settings_by_id_.find(extension->id());
234 if (iter_id != settings_by_id_.end())
235 return iter_id->second->runtime_blocked_hosts.MatchesURL(url);
236 return default_settings_->runtime_blocked_hosts.MatchesURL(url);
237}
238
dchengc963c7142016-04-08 03:55:22239std::unique_ptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
binjin685ade82014-11-06 09:53:56240 const Extension* extension) const {
binjine6b58b52014-10-31 01:55:57241 // Only api permissions are supported currently.
dchengc963c7142016-04-08 03:55:22242 return std::unique_ptr<const PermissionSet>(new PermissionSet(
binjin685ade82014-11-06 09:53:56243 GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
244 URLPatternSet(), URLPatternSet()));
binjine6b58b52014-10-31 01:55:57245}
246
247bool ExtensionManagement::IsPermissionSetAllowed(
binjin685ade82014-11-06 09:53:56248 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:49249 const PermissionSet& perms) const {
vmpstrae72b082016-07-25 21:55:47250 for (auto* blocked_api : GetBlockedAPIPermissions(extension)) {
rdevlin.cronine2d0fd02015-09-24 22:35:49251 if (perms.HasAPIPermission(blocked_api->id()))
binjine6b58b52014-10-31 01:55:57252 return false;
253 }
254 return true;
255}
256
nrpeter2362e7e2017-05-10 17:21:26257const std::string ExtensionManagement::BlockedInstallMessage(
258 const ExtensionId& id) const {
259 auto iter_id = settings_by_id_.find(id);
260 if (iter_id != settings_by_id_.end())
261 return iter_id->second->blocked_install_message;
262 return default_settings_->blocked_install_message;
263}
264
binjin8e3d0182014-12-04 16:44:28265bool ExtensionManagement::CheckMinimumVersion(
266 const Extension* extension,
267 std::string* required_version) const {
268 auto iter = settings_by_id_.find(extension->id());
269 // If there are no minimum version required for |extension|, return true.
270 if (iter == settings_by_id_.end() || !iter->second->minimum_version_required)
271 return true;
Devlin Cronin03bf2d22017-12-20 08:21:05272 bool meets_requirement = extension->version().CompareTo(
273 *iter->second->minimum_version_required) >= 0;
binjin8e3d0182014-12-04 16:44:28274 // Output a human readable version string for prompting if necessary.
275 if (!meets_requirement && required_version)
276 *required_version = iter->second->minimum_version_required->GetString();
277 return meets_requirement;
278}
279
binjin5f405ef2014-09-03 21:23:16280void ExtensionManagement::Refresh() {
rkaplowdd66a1342015-03-05 00:31:49281 TRACE_EVENT0("browser,startup", "ExtensionManagement::Refresh");
282 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ExtensionManagement_RefreshTime");
binjin5f405ef2014-09-03 21:23:16283 // Load all extension management settings preferences.
284 const base::ListValue* allowed_list_pref =
285 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28286 pref_names::kInstallAllowList, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16287 // Allow user to use preference to block certain extensions. Note that policy
288 // managed forcelist or whitelist will always override this.
289 const base::ListValue* denied_list_pref =
290 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28291 pref_names::kInstallDenyList, false, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16292 const base::DictionaryValue* forced_list_pref =
293 static_cast<const base::DictionaryValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28294 pref_names::kInstallForceList, true, base::Value::Type::DICTIONARY));
achuith4607f072017-03-08 11:49:13295 const base::DictionaryValue* login_screen_app_list_pref = nullptr;
296 if (is_signin_profile_) {
297 login_screen_app_list_pref = static_cast<const base::DictionaryValue*>(
298 LoadPreference(pref_names::kInstallLoginScreenAppList, true,
299 base::Value::Type::DICTIONARY));
300 }
binjin5f405ef2014-09-03 21:23:16301 const base::ListValue* install_sources_pref =
302 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28303 pref_names::kAllowedInstallSites, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16304 const base::ListValue* allowed_types_pref =
305 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28306 pref_names::kAllowedTypes, true, base::Value::Type::LIST));
binjinb2454382014-09-22 15:17:43307 const base::DictionaryValue* dict_pref =
308 static_cast<const base::DictionaryValue*>(
309 LoadPreference(pref_names::kExtensionManagement,
310 true,
jdoerriedc72ee942016-12-07 15:43:28311 base::Value::Type::DICTIONARY));
binjin5f405ef2014-09-03 21:23:16312
313 // Reset all settings.
binjin81d7c552014-10-02 11:47:12314 global_settings_.reset(new internal::GlobalSettings());
binjin5f405ef2014-09-03 21:23:16315 settings_by_id_.clear();
binjin81d7c552014-10-02 11:47:12316 default_settings_.reset(new internal::IndividualSettings());
binjin5f405ef2014-09-03 21:23:16317
318 // Parse default settings.
jdoerrie122c4da2017-03-06 11:12:04319 const base::Value wildcard("*");
binjin5f405ef2014-09-03 21:23:16320 if (denied_list_pref &&
321 denied_list_pref->Find(wildcard) != denied_list_pref->end()) {
binjin81d7c552014-10-02 11:47:12322 default_settings_->installation_mode = INSTALLATION_BLOCKED;
binjin5f405ef2014-09-03 21:23:16323 }
324
binjinb2454382014-09-22 15:17:43325 const base::DictionaryValue* subdict = NULL;
326 if (dict_pref &&
327 dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) {
binjin81d7c552014-10-02 11:47:12328 if (!default_settings_->Parse(
329 subdict, internal::IndividualSettings::SCOPE_DEFAULT)) {
binjinb2454382014-09-22 15:17:43330 LOG(WARNING) << "Default extension management settings parsing error.";
binjin81d7c552014-10-02 11:47:12331 default_settings_->Reset();
binjinb2454382014-09-22 15:17:43332 }
333
334 // Settings from new preference have higher priority over legacy ones.
335 const base::ListValue* list_value = NULL;
336 if (subdict->GetList(schema_constants::kInstallSources, &list_value))
337 install_sources_pref = list_value;
338 if (subdict->GetList(schema_constants::kAllowedTypes, &list_value))
339 allowed_types_pref = list_value;
340 }
341
binjin5f405ef2014-09-03 21:23:16342 // Parse legacy preferences.
343 ExtensionId id;
344
345 if (allowed_list_pref) {
346 for (base::ListValue::const_iterator it = allowed_list_pref->begin();
347 it != allowed_list_pref->end(); ++it) {
jdoerriea5676c62017-04-11 18:09:14348 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16349 AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
350 }
351 }
352
353 if (denied_list_pref) {
354 for (base::ListValue::const_iterator it = denied_list_pref->begin();
355 it != denied_list_pref->end(); ++it) {
jdoerriea5676c62017-04-11 18:09:14356 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16357 AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
358 }
359 }
360
achuith4607f072017-03-08 11:49:13361 UpdateForcedExtensions(forced_list_pref);
362 UpdateForcedExtensions(login_screen_app_list_pref);
binjin5f405ef2014-09-03 21:23:16363
364 if (install_sources_pref) {
binjin81d7c552014-10-02 11:47:12365 global_settings_->has_restricted_install_sources = true;
binjin5f405ef2014-09-03 21:23:16366 for (base::ListValue::const_iterator it = install_sources_pref->begin();
367 it != install_sources_pref->end(); ++it) {
binjinb2454382014-09-22 15:17:43368 std::string url_pattern;
jdoerriea5676c62017-04-11 18:09:14369 if (it->GetAsString(&url_pattern)) {
binjinb2454382014-09-22 15:17:43370 URLPattern entry(URLPattern::SCHEME_ALL);
binjin5f405ef2014-09-03 21:23:16371 if (entry.Parse(url_pattern) == URLPattern::PARSE_SUCCESS) {
binjin81d7c552014-10-02 11:47:12372 global_settings_->install_sources.AddPattern(entry);
binjin5f405ef2014-09-03 21:23:16373 } else {
374 LOG(WARNING) << "Invalid URL pattern in for preference "
375 << pref_names::kAllowedInstallSites << ": "
376 << url_pattern << ".";
377 }
378 }
379 }
380 }
381
382 if (allowed_types_pref) {
binjin81d7c552014-10-02 11:47:12383 global_settings_->has_restricted_allowed_types = true;
binjin5f405ef2014-09-03 21:23:16384 for (base::ListValue::const_iterator it = allowed_types_pref->begin();
385 it != allowed_types_pref->end(); ++it) {
386 int int_value;
binjinb2454382014-09-22 15:17:43387 std::string string_value;
jdoerriea5676c62017-04-11 18:09:14388 if (it->GetAsInteger(&int_value) && int_value >= 0 &&
binjin5f405ef2014-09-03 21:23:16389 int_value < Manifest::Type::NUM_LOAD_TYPES) {
binjin81d7c552014-10-02 11:47:12390 global_settings_->allowed_types.push_back(
binjin5f405ef2014-09-03 21:23:16391 static_cast<Manifest::Type>(int_value));
jdoerriea5676c62017-04-11 18:09:14392 } else if (it->GetAsString(&string_value)) {
binjinb2454382014-09-22 15:17:43393 Manifest::Type manifest_type =
394 schema_constants::GetManifestType(string_value);
395 if (manifest_type != Manifest::TYPE_UNKNOWN)
binjin81d7c552014-10-02 11:47:12396 global_settings_->allowed_types.push_back(manifest_type);
binjin5f405ef2014-09-03 21:23:16397 }
398 }
399 }
400
binjinb2454382014-09-22 15:17:43401 if (dict_pref) {
402 // Parse new extension management preference.
403 for (base::DictionaryValue::Iterator iter(*dict_pref); !iter.IsAtEnd();
404 iter.Advance()) {
405 if (iter.key() == schema_constants::kWildcard)
406 continue;
binjin81d7c552014-10-02 11:47:12407 if (!iter.value().GetAsDictionary(&subdict))
binjinb2454382014-09-22 15:17:43408 continue;
brettw66d1b81b2015-07-06 19:29:40409 if (base::StartsWith(iter.key(), schema_constants::kUpdateUrlPrefix,
410 base::CompareCase::SENSITIVE)) {
binjin685ade82014-11-06 09:53:56411 const std::string& update_url =
412 iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
413 if (!GURL(update_url).is_valid()) {
414 LOG(WARNING) << "Invalid update URL: " << update_url << ".";
415 continue;
416 }
417 internal::IndividualSettings* by_update_url =
418 AccessByUpdateUrl(update_url);
419 if (!by_update_url->Parse(
420 subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
421 settings_by_update_url_.erase(update_url);
422 LOG(WARNING) << "Malformed Extension Management settings for "
423 "extensions with update url: " << update_url << ".";
424 }
425 } else {
426 const std::string& extension_id = iter.key();
427 if (!crx_file::id_util::IdIsValid(extension_id)) {
428 LOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
429 continue;
430 }
431 internal::IndividualSettings* by_id = AccessById(extension_id);
432 if (!by_id->Parse(subdict,
433 internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
434 settings_by_id_.erase(extension_id);
435 LOG(WARNING) << "Malformed Extension Management settings for "
436 << extension_id << ".";
437 }
binjinb2454382014-09-22 15:17:43438 }
439 }
440 }
binjin5f405ef2014-09-03 21:23:16441}
442
binjin5f405ef2014-09-03 21:23:16443const base::Value* ExtensionManagement::LoadPreference(
444 const char* pref_name,
445 bool force_managed,
446 base::Value::Type expected_type) {
binjine6b58b52014-10-31 01:55:57447 if (!pref_service_)
448 return nullptr;
binjin5f405ef2014-09-03 21:23:16449 const PrefService::Preference* pref =
450 pref_service_->FindPreference(pref_name);
451 if (pref && !pref->IsDefaultValue() &&
452 (!force_managed || pref->IsManaged())) {
453 const base::Value* value = pref->GetValue();
jdoerrie1f536b22017-10-23 17:15:11454 if (value && value->type() == expected_type)
binjin5f405ef2014-09-03 21:23:16455 return value;
456 }
binjine6b58b52014-10-31 01:55:57457 return nullptr;
binjin5f405ef2014-09-03 21:23:16458}
459
binjin1569c9b2014-09-05 13:33:18460void ExtensionManagement::OnExtensionPrefChanged() {
461 Refresh();
462 NotifyExtensionManagementPrefChanged();
463}
464
465void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
ericwilligersb5f79de2016-10-19 04:15:10466 for (auto& observer : observer_list_)
467 observer.OnExtensionManagementSettingsChanged();
binjin1569c9b2014-09-05 13:33:18468}
469
achuith4607f072017-03-08 11:49:13470std::unique_ptr<base::DictionaryValue>
471ExtensionManagement::GetInstallListByMode(
472 InstallationMode installation_mode) const {
473 auto extension_dict = base::MakeUnique<base::DictionaryValue>();
474 for (const auto& entry : settings_by_id_) {
475 if (entry.second->installation_mode == installation_mode) {
476 ExternalPolicyLoader::AddExtension(extension_dict.get(), entry.first,
477 entry.second->update_url);
478 }
479 }
480 return extension_dict;
481}
482
483void ExtensionManagement::UpdateForcedExtensions(
484 const base::DictionaryValue* extension_dict) {
485 if (!extension_dict)
486 return;
487
488 std::string update_url;
489 for (base::DictionaryValue::Iterator it(*extension_dict); !it.IsAtEnd();
490 it.Advance()) {
491 if (!crx_file::id_util::IdIsValid(it.key()))
492 continue;
493 const base::DictionaryValue* dict_value = nullptr;
494 if (it.value().GetAsDictionary(&dict_value) &&
495 dict_value->GetStringWithoutPathExpansion(
496 ExternalProviderImpl::kExternalUpdateUrl, &update_url)) {
497 internal::IndividualSettings* by_id = AccessById(it.key());
498 by_id->installation_mode = INSTALLATION_FORCED;
499 by_id->update_url = update_url;
500 }
501 }
502}
503
binjin81d7c552014-10-02 11:47:12504internal::IndividualSettings* ExtensionManagement::AccessById(
binjin5f405ef2014-09-03 21:23:16505 const ExtensionId& id) {
506 DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id;
avi3ec9c0d2016-12-27 22:38:06507 std::unique_ptr<internal::IndividualSettings>& settings = settings_by_id_[id];
508 if (!settings) {
509 settings =
510 base::MakeUnique<internal::IndividualSettings>(default_settings_.get());
binjin81d7c552014-10-02 11:47:12511 }
avi3ec9c0d2016-12-27 22:38:06512 return settings.get();
binjin5f405ef2014-09-03 21:23:16513}
514
binjin685ade82014-11-06 09:53:56515internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
516 const std::string& update_url) {
517 DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
avi3ec9c0d2016-12-27 22:38:06518 std::unique_ptr<internal::IndividualSettings>& settings =
519 settings_by_update_url_[update_url];
520 if (!settings) {
521 settings =
522 base::MakeUnique<internal::IndividualSettings>(default_settings_.get());
binjin685ade82014-11-06 09:53:56523 }
avi3ec9c0d2016-12-27 22:38:06524 return settings.get();
binjin685ade82014-11-06 09:53:56525}
526
binjin1569c9b2014-09-05 13:33:18527ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(
528 content::BrowserContext* context) {
529 return static_cast<ExtensionManagement*>(
530 GetInstance()->GetServiceForBrowserContext(context, true));
531}
532
533ExtensionManagementFactory* ExtensionManagementFactory::GetInstance() {
olli.raula36aa8be2015-09-10 11:14:22534 return base::Singleton<ExtensionManagementFactory>::get();
binjin1569c9b2014-09-05 13:33:18535}
536
537ExtensionManagementFactory::ExtensionManagementFactory()
538 : BrowserContextKeyedServiceFactory(
539 "ExtensionManagement",
540 BrowserContextDependencyManager::GetInstance()) {
541}
542
543ExtensionManagementFactory::~ExtensionManagementFactory() {
544}
545
546KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor(
547 content::BrowserContext* context) const {
rkaplowdd66a1342015-03-05 00:31:49548 TRACE_EVENT0("browser,startup",
549 "ExtensionManagementFactory::BuildServiceInstanceFor");
achuith4607f072017-03-08 11:49:13550 Profile* profile = Profile::FromBrowserContext(context);
551 bool is_signin_profile = false;
552#if defined(OS_CHROMEOS)
553 is_signin_profile = chromeos::ProfileHelper::IsSigninProfile(profile);
554#endif
555 return new ExtensionManagement(profile->GetPrefs(), is_signin_profile);
binjin1569c9b2014-09-05 13:33:18556}
557
binjin9733df12014-09-08 15:21:21558content::BrowserContext* ExtensionManagementFactory::GetBrowserContextToUse(
559 content::BrowserContext* context) const {
560 return chrome::GetBrowserContextRedirectedInIncognito(context);
561}
562
binjinb2454382014-09-22 15:17:43563void ExtensionManagementFactory::RegisterProfilePrefs(
564 user_prefs::PrefRegistrySyncable* user_prefs) {
raymesaa608722015-04-27 03:00:25565 user_prefs->RegisterDictionaryPref(pref_names::kExtensionManagement);
binjinb2454382014-09-22 15:17:43566}
567
binjin5f405ef2014-09-03 21:23:16568} // namespace extensions