blob: 313ce222c9f4cf9c8acdcc8614b0c6712ad238c0 [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"
rkaplowdd66a1342015-03-05 00:31:4912#include "base/metrics/histogram_macros.h"
tripta.g0ac673a2017-07-07 05:45:0913#include "base/stl_util.h"
binjine6b58b52014-10-31 01:55:5714#include "base/strings/string16.h"
binjinb2454382014-09-22 15:17:4315#include "base/strings/string_util.h"
rkaplowdd66a1342015-03-05 00:31:4916#include "base/trace_event/trace_event.h"
binjin8e3d0182014-12-04 16:44:2817#include "base/version.h"
binjinb2454382014-09-22 15:17:4318#include "chrome/browser/extensions/extension_management_constants.h"
binjin81d7c552014-10-02 11:47:1219#include "chrome/browser/extensions/extension_management_internal.h"
binjin30301062014-09-08 20:27:3420#include "chrome/browser/extensions/external_policy_loader.h"
binjin5f405ef2014-09-03 21:23:1621#include "chrome/browser/extensions/external_provider_impl.h"
binjine6b58b52014-10-31 01:55:5722#include "chrome/browser/extensions/permissions_based_management_policy_provider.h"
binjin1569c9b2014-09-05 13:33:1823#include "chrome/browser/extensions/standard_management_policy_provider.h"
binjin9733df12014-09-08 15:21:2124#include "chrome/browser/profiles/incognito_helpers.h"
binjin1569c9b2014-09-05 13:33:1825#include "chrome/browser/profiles/profile.h"
binjin5f405ef2014-09-03 21:23:1626#include "components/crx_file/id_util.h"
binjin1569c9b2014-09-05 13:33:1827#include "components/keyed_service/content/browser_context_dependency_manager.h"
binjinb2454382014-09-22 15:17:4328#include "components/pref_registry/pref_registry_syncable.h"
brettwb1fc1b82016-02-02 00:19:0829#include "components/prefs/pref_service.h"
binjin5f405ef2014-09-03 21:23:1630#include "extensions/browser/pref_names.h"
rdevlin.cronin0670b562016-07-02 02:05:4331#include "extensions/common/extension.h"
binjin685ade82014-11-06 09:53:5632#include "extensions/common/manifest_constants.h"
binjine6b58b52014-10-31 01:55:5733#include "extensions/common/permissions/api_permission_set.h"
34#include "extensions/common/permissions/permission_set.h"
binjin5f405ef2014-09-03 21:23:1635#include "extensions/common/url_pattern.h"
binjin311ecdf2014-09-12 22:56:5236#include "url/gurl.h"
binjin5f405ef2014-09-03 21:23:1637
achuith4607f072017-03-08 11:49:1338#if defined(OS_CHROMEOS)
39#include "chrome/browser/chromeos/profiles/profile_helper.h"
40#endif
41
binjin5f405ef2014-09-03 21:23:1642namespace extensions {
43
achuith4607f072017-03-08 11:49:1344ExtensionManagement::ExtensionManagement(PrefService* pref_service,
45 bool is_signin_profile)
46 : pref_service_(pref_service), is_signin_profile_(is_signin_profile) {
rkaplowdd66a1342015-03-05 00:31:4947 TRACE_EVENT0("browser,startup",
48 "ExtensionManagement::ExtensionManagement::ctor");
binjin1569c9b2014-09-05 13:33:1849 pref_change_registrar_.Init(pref_service_);
50 base::Closure pref_change_callback = base::Bind(
51 &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this));
52 pref_change_registrar_.Add(pref_names::kInstallAllowList,
53 pref_change_callback);
54 pref_change_registrar_.Add(pref_names::kInstallDenyList,
55 pref_change_callback);
56 pref_change_registrar_.Add(pref_names::kInstallForceList,
57 pref_change_callback);
achuith4607f072017-03-08 11:49:1358 pref_change_registrar_.Add(pref_names::kInstallLoginScreenAppList,
59 pref_change_callback);
binjin1569c9b2014-09-05 13:33:1860 pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
61 pref_change_callback);
62 pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
binjinb2454382014-09-22 15:17:4363 pref_change_registrar_.Add(pref_names::kExtensionManagement,
64 pref_change_callback);
binjin81d7c552014-10-02 11:47:1265 // Note that both |global_settings_| and |default_settings_| will be null
66 // before first call to Refresh(), so in order to resolve this, Refresh() must
67 // be called in the initialization of ExtensionManagement.
binjin1569c9b2014-09-05 13:33:1868 Refresh();
lazyboy4aeef202016-09-07 21:28:5969 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1170 std::make_unique<StandardManagementPolicyProvider>(this));
lazyboy4aeef202016-09-07 21:28:5971 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1172 std::make_unique<PermissionsBasedManagementPolicyProvider>(this));
binjin5f405ef2014-09-03 21:23:1673}
74
75ExtensionManagement::~ExtensionManagement() {
76}
77
binjine6b58b52014-10-31 01:55:5778void ExtensionManagement::Shutdown() {
79 pref_change_registrar_.RemoveAll();
80 pref_service_ = nullptr;
81}
82
binjin1569c9b2014-09-05 13:33:1883void ExtensionManagement::AddObserver(Observer* observer) {
84 observer_list_.AddObserver(observer);
85}
86
87void ExtensionManagement::RemoveObserver(Observer* observer) {
88 observer_list_.RemoveObserver(observer);
89}
90
lazyboy4aeef202016-09-07 21:28:5991const std::vector<std::unique_ptr<ManagementPolicy::Provider>>&
92ExtensionManagement::GetProviders() const {
93 return providers_;
binjin1569c9b2014-09-05 13:33:1894}
95
binjin81d7c552014-10-02 11:47:1296bool ExtensionManagement::BlacklistedByDefault() const {
97 return default_settings_->installation_mode == INSTALLATION_BLOCKED;
98}
99
100ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
binjin685ade82014-11-06 09:53:56101 const Extension* extension) const {
102 // Check per-extension installation mode setting first.
103 auto iter_id = settings_by_id_.find(extension->id());
104 if (iter_id != settings_by_id_.end())
105 return iter_id->second->installation_mode;
106 std::string update_url;
107 // Check per-update-url installation mode setting.
108 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
109 &update_url)) {
110 auto iter_update_url = settings_by_update_url_.find(update_url);
111 if (iter_update_url != settings_by_update_url_.end())
112 return iter_update_url->second->installation_mode;
113 }
114 // Fall back to default installation mode setting.
115 return default_settings_->installation_mode;
binjin1569c9b2014-09-05 13:33:18116}
117
dchengc963c7142016-04-08 03:55:22118std::unique_ptr<base::DictionaryValue>
hashimoto146e05a2016-11-18 07:42:53119ExtensionManagement::GetForceInstallList() const {
achuith4607f072017-03-08 11:49:13120 return GetInstallListByMode(INSTALLATION_FORCED);
binjincccacef2014-10-13 19:00:20121}
122
dchengc963c7142016-04-08 03:55:22123std::unique_ptr<base::DictionaryValue>
binjincccacef2014-10-13 19:00:20124ExtensionManagement::GetRecommendedInstallList() const {
achuith4607f072017-03-08 11:49:13125 return GetInstallListByMode(INSTALLATION_RECOMMENDED);
binjin30301062014-09-08 20:27:34126}
127
binjinc641add2014-10-15 16:20:45128bool ExtensionManagement::IsInstallationExplicitlyAllowed(
129 const ExtensionId& id) const {
avi3ec9c0d2016-12-27 22:38:06130 auto it = settings_by_id_.find(id);
binjinc641add2014-10-15 16:20:45131 // No settings explicitly specified for |id|.
132 if (it == settings_by_id_.end())
133 return false;
134 // Checks if the extension is on the automatically installed list or
135 // install white-list.
136 InstallationMode mode = it->second->installation_mode;
137 return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
138 mode == INSTALLATION_ALLOWED;
binjin30301062014-09-08 20:27:34139}
140
binjin81d7c552014-10-02 11:47:12141bool ExtensionManagement::IsOffstoreInstallAllowed(
142 const GURL& url,
143 const GURL& referrer_url) const {
binjin311ecdf2014-09-12 22:56:52144 // No allowed install sites specified, disallow by default.
binjin81d7c552014-10-02 11:47:12145 if (!global_settings_->has_restricted_install_sources)
binjin311ecdf2014-09-12 22:56:52146 return false;
147
binjin81d7c552014-10-02 11:47:12148 const URLPatternSet& url_patterns = global_settings_->install_sources;
binjin311ecdf2014-09-12 22:56:52149
150 if (!url_patterns.MatchesURL(url))
151 return false;
152
153 // The referrer URL must also be whitelisted, unless the URL has the file
154 // scheme (there's no referrer for those URLs).
155 return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url);
156}
157
binjin81d7c552014-10-02 11:47:12158bool ExtensionManagement::IsAllowedManifestType(
159 Manifest::Type manifest_type) const {
160 if (!global_settings_->has_restricted_allowed_types)
161 return true;
162 const std::vector<Manifest::Type>& allowed_types =
163 global_settings_->allowed_types;
tripta.g0ac673a2017-07-07 05:45:09164 return base::ContainsValue(allowed_types, manifest_type);
binjin1569c9b2014-09-05 13:33:18165}
166
binjin685ade82014-11-06 09:53:56167APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
168 const Extension* extension) const {
169 // Fetch per-extension blocked permissions setting.
170 auto iter_id = settings_by_id_.find(extension->id());
171
172 // Fetch per-update-url blocked permissions setting.
173 std::string update_url;
174 auto iter_update_url = settings_by_update_url_.end();
175 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
176 &update_url)) {
177 iter_update_url = settings_by_update_url_.find(update_url);
178 }
179
180 if (iter_id != settings_by_id_.end() &&
181 iter_update_url != settings_by_update_url_.end()) {
182 // Blocked permissions setting are specified in both per-extension and
183 // per-update-url settings, try to merge them.
184 APIPermissionSet merged;
185 APIPermissionSet::Union(iter_id->second->blocked_permissions,
186 iter_update_url->second->blocked_permissions,
187 &merged);
188 return merged;
189 }
190 // Check whether if in one of them, setting is specified.
191 if (iter_id != settings_by_id_.end())
192 return iter_id->second->blocked_permissions;
193 if (iter_update_url != settings_by_update_url_.end())
194 return iter_update_url->second->blocked_permissions;
195 // Fall back to the default blocked permissions setting.
196 return default_settings_->blocked_permissions;
binjine6b58b52014-10-31 01:55:57197}
198
Devlin Cronin7e0f41ff2018-05-16 17:19:36199const URLPatternSet& ExtensionManagement::GetDefaultPolicyBlockedHosts() const {
200 return default_settings_->policy_blocked_hosts;
nrpetere33d2a5b2017-04-25 00:12:31201}
202
Devlin Cronin7e0f41ff2018-05-16 17:19:36203const URLPatternSet& ExtensionManagement::GetDefaultPolicyAllowedHosts() const {
204 return default_settings_->policy_allowed_hosts;
nrpetere33d2a5b2017-04-25 00:12:31205}
206
Devlin Cronin7e0f41ff2018-05-16 17:19:36207const URLPatternSet& ExtensionManagement::GetPolicyBlockedHosts(
nrpeter40e16382017-04-13 17:34:58208 const Extension* extension) const {
209 auto iter_id = settings_by_id_.find(extension->id());
210 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36211 return iter_id->second->policy_blocked_hosts;
212 return default_settings_->policy_blocked_hosts;
nrpeter40e16382017-04-13 17:34:58213}
214
Devlin Cronin7e0f41ff2018-05-16 17:19:36215const URLPatternSet& ExtensionManagement::GetPolicyAllowedHosts(
nrpeter40e16382017-04-13 17:34:58216 const Extension* extension) const {
217 auto iter_id = settings_by_id_.find(extension->id());
218 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36219 return iter_id->second->policy_allowed_hosts;
220 return default_settings_->policy_allowed_hosts;
nrpeter40e16382017-04-13 17:34:58221}
222
Devlin Cronin7e0f41ff2018-05-16 17:19:36223bool ExtensionManagement::UsesDefaultPolicyHostRestrictions(
nrpetere33d2a5b2017-04-25 00:12:31224 const Extension* extension) const {
225 return settings_by_id_.find(extension->id()) == settings_by_id_.end();
226}
227
Devlin Cronin7e0f41ff2018-05-16 17:19:36228bool ExtensionManagement::IsPolicyBlockedHost(const Extension* extension,
229 const GURL& url) const {
nrpeter40e16382017-04-13 17:34:58230 auto iter_id = settings_by_id_.find(extension->id());
231 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36232 return iter_id->second->policy_blocked_hosts.MatchesURL(url);
233 return default_settings_->policy_blocked_hosts.MatchesURL(url);
nrpeter40e16382017-04-13 17:34:58234}
235
dchengc963c7142016-04-08 03:55:22236std::unique_ptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
binjin685ade82014-11-06 09:53:56237 const Extension* extension) const {
binjine6b58b52014-10-31 01:55:57238 // Only api permissions are supported currently.
dchengc963c7142016-04-08 03:55:22239 return std::unique_ptr<const PermissionSet>(new PermissionSet(
binjin685ade82014-11-06 09:53:56240 GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
241 URLPatternSet(), URLPatternSet()));
binjine6b58b52014-10-31 01:55:57242}
243
244bool ExtensionManagement::IsPermissionSetAllowed(
binjin685ade82014-11-06 09:53:56245 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:49246 const PermissionSet& perms) const {
vmpstrae72b082016-07-25 21:55:47247 for (auto* blocked_api : GetBlockedAPIPermissions(extension)) {
rdevlin.cronine2d0fd02015-09-24 22:35:49248 if (perms.HasAPIPermission(blocked_api->id()))
binjine6b58b52014-10-31 01:55:57249 return false;
250 }
251 return true;
252}
253
nrpeter2362e7e2017-05-10 17:21:26254const std::string ExtensionManagement::BlockedInstallMessage(
255 const ExtensionId& id) const {
256 auto iter_id = settings_by_id_.find(id);
257 if (iter_id != settings_by_id_.end())
258 return iter_id->second->blocked_install_message;
259 return default_settings_->blocked_install_message;
260}
261
binjin8e3d0182014-12-04 16:44:28262bool ExtensionManagement::CheckMinimumVersion(
263 const Extension* extension,
264 std::string* required_version) const {
265 auto iter = settings_by_id_.find(extension->id());
266 // If there are no minimum version required for |extension|, return true.
267 if (iter == settings_by_id_.end() || !iter->second->minimum_version_required)
268 return true;
Devlin Cronin03bf2d22017-12-20 08:21:05269 bool meets_requirement = extension->version().CompareTo(
270 *iter->second->minimum_version_required) >= 0;
binjin8e3d0182014-12-04 16:44:28271 // Output a human readable version string for prompting if necessary.
272 if (!meets_requirement && required_version)
273 *required_version = iter->second->minimum_version_required->GetString();
274 return meets_requirement;
275}
276
binjin5f405ef2014-09-03 21:23:16277void ExtensionManagement::Refresh() {
rkaplowdd66a1342015-03-05 00:31:49278 TRACE_EVENT0("browser,startup", "ExtensionManagement::Refresh");
279 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ExtensionManagement_RefreshTime");
binjin5f405ef2014-09-03 21:23:16280 // Load all extension management settings preferences.
281 const base::ListValue* allowed_list_pref =
282 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28283 pref_names::kInstallAllowList, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16284 // Allow user to use preference to block certain extensions. Note that policy
285 // managed forcelist or whitelist will always override this.
286 const base::ListValue* denied_list_pref =
287 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28288 pref_names::kInstallDenyList, false, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16289 const base::DictionaryValue* forced_list_pref =
290 static_cast<const base::DictionaryValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28291 pref_names::kInstallForceList, true, base::Value::Type::DICTIONARY));
achuith4607f072017-03-08 11:49:13292 const base::DictionaryValue* login_screen_app_list_pref = nullptr;
293 if (is_signin_profile_) {
294 login_screen_app_list_pref = static_cast<const base::DictionaryValue*>(
295 LoadPreference(pref_names::kInstallLoginScreenAppList, true,
296 base::Value::Type::DICTIONARY));
297 }
binjin5f405ef2014-09-03 21:23:16298 const base::ListValue* install_sources_pref =
299 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28300 pref_names::kAllowedInstallSites, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16301 const base::ListValue* allowed_types_pref =
302 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28303 pref_names::kAllowedTypes, true, base::Value::Type::LIST));
binjinb2454382014-09-22 15:17:43304 const base::DictionaryValue* dict_pref =
305 static_cast<const base::DictionaryValue*>(
306 LoadPreference(pref_names::kExtensionManagement,
307 true,
jdoerriedc72ee942016-12-07 15:43:28308 base::Value::Type::DICTIONARY));
binjin5f405ef2014-09-03 21:23:16309
310 // Reset all settings.
binjin81d7c552014-10-02 11:47:12311 global_settings_.reset(new internal::GlobalSettings());
binjin5f405ef2014-09-03 21:23:16312 settings_by_id_.clear();
binjin81d7c552014-10-02 11:47:12313 default_settings_.reset(new internal::IndividualSettings());
binjin5f405ef2014-09-03 21:23:16314
315 // Parse default settings.
jdoerrie122c4da2017-03-06 11:12:04316 const base::Value wildcard("*");
binjin5f405ef2014-09-03 21:23:16317 if (denied_list_pref &&
318 denied_list_pref->Find(wildcard) != denied_list_pref->end()) {
binjin81d7c552014-10-02 11:47:12319 default_settings_->installation_mode = INSTALLATION_BLOCKED;
binjin5f405ef2014-09-03 21:23:16320 }
321
binjinb2454382014-09-22 15:17:43322 const base::DictionaryValue* subdict = NULL;
323 if (dict_pref &&
324 dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) {
binjin81d7c552014-10-02 11:47:12325 if (!default_settings_->Parse(
326 subdict, internal::IndividualSettings::SCOPE_DEFAULT)) {
binjinb2454382014-09-22 15:17:43327 LOG(WARNING) << "Default extension management settings parsing error.";
binjin81d7c552014-10-02 11:47:12328 default_settings_->Reset();
binjinb2454382014-09-22 15:17:43329 }
330
331 // Settings from new preference have higher priority over legacy ones.
332 const base::ListValue* list_value = NULL;
333 if (subdict->GetList(schema_constants::kInstallSources, &list_value))
334 install_sources_pref = list_value;
335 if (subdict->GetList(schema_constants::kAllowedTypes, &list_value))
336 allowed_types_pref = list_value;
337 }
338
binjin5f405ef2014-09-03 21:23:16339 // Parse legacy preferences.
340 ExtensionId id;
341
342 if (allowed_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02343 for (auto it = allowed_list_pref->begin(); it != allowed_list_pref->end();
344 ++it) {
jdoerriea5676c62017-04-11 18:09:14345 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16346 AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
347 }
348 }
349
350 if (denied_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02351 for (auto it = denied_list_pref->begin(); it != denied_list_pref->end();
352 ++it) {
jdoerriea5676c62017-04-11 18:09:14353 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16354 AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
355 }
356 }
357
achuith4607f072017-03-08 11:49:13358 UpdateForcedExtensions(forced_list_pref);
359 UpdateForcedExtensions(login_screen_app_list_pref);
binjin5f405ef2014-09-03 21:23:16360
361 if (install_sources_pref) {
binjin81d7c552014-10-02 11:47:12362 global_settings_->has_restricted_install_sources = true;
jdoerrie13cd648c82018-10-02 21:21:02363 for (auto it = install_sources_pref->begin();
binjin5f405ef2014-09-03 21:23:16364 it != install_sources_pref->end(); ++it) {
binjinb2454382014-09-22 15:17:43365 std::string url_pattern;
jdoerriea5676c62017-04-11 18:09:14366 if (it->GetAsString(&url_pattern)) {
binjinb2454382014-09-22 15:17:43367 URLPattern entry(URLPattern::SCHEME_ALL);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18368 if (entry.Parse(url_pattern) == URLPattern::ParseResult::kSuccess) {
binjin81d7c552014-10-02 11:47:12369 global_settings_->install_sources.AddPattern(entry);
binjin5f405ef2014-09-03 21:23:16370 } else {
371 LOG(WARNING) << "Invalid URL pattern in for preference "
372 << pref_names::kAllowedInstallSites << ": "
373 << url_pattern << ".";
374 }
375 }
376 }
377 }
378
379 if (allowed_types_pref) {
binjin81d7c552014-10-02 11:47:12380 global_settings_->has_restricted_allowed_types = true;
jdoerrie13cd648c82018-10-02 21:21:02381 for (auto it = allowed_types_pref->begin(); it != allowed_types_pref->end();
382 ++it) {
binjin5f405ef2014-09-03 21:23:16383 int int_value;
binjinb2454382014-09-22 15:17:43384 std::string string_value;
jdoerriea5676c62017-04-11 18:09:14385 if (it->GetAsInteger(&int_value) && int_value >= 0 &&
binjin5f405ef2014-09-03 21:23:16386 int_value < Manifest::Type::NUM_LOAD_TYPES) {
binjin81d7c552014-10-02 11:47:12387 global_settings_->allowed_types.push_back(
binjin5f405ef2014-09-03 21:23:16388 static_cast<Manifest::Type>(int_value));
jdoerriea5676c62017-04-11 18:09:14389 } else if (it->GetAsString(&string_value)) {
binjinb2454382014-09-22 15:17:43390 Manifest::Type manifest_type =
391 schema_constants::GetManifestType(string_value);
392 if (manifest_type != Manifest::TYPE_UNKNOWN)
binjin81d7c552014-10-02 11:47:12393 global_settings_->allowed_types.push_back(manifest_type);
binjin5f405ef2014-09-03 21:23:16394 }
395 }
396 }
397
binjinb2454382014-09-22 15:17:43398 if (dict_pref) {
399 // Parse new extension management preference.
400 for (base::DictionaryValue::Iterator iter(*dict_pref); !iter.IsAtEnd();
401 iter.Advance()) {
402 if (iter.key() == schema_constants::kWildcard)
403 continue;
binjin81d7c552014-10-02 11:47:12404 if (!iter.value().GetAsDictionary(&subdict))
binjinb2454382014-09-22 15:17:43405 continue;
brettw66d1b81b2015-07-06 19:29:40406 if (base::StartsWith(iter.key(), schema_constants::kUpdateUrlPrefix,
407 base::CompareCase::SENSITIVE)) {
binjin685ade82014-11-06 09:53:56408 const std::string& update_url =
409 iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
410 if (!GURL(update_url).is_valid()) {
411 LOG(WARNING) << "Invalid update URL: " << update_url << ".";
412 continue;
413 }
414 internal::IndividualSettings* by_update_url =
415 AccessByUpdateUrl(update_url);
416 if (!by_update_url->Parse(
417 subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
418 settings_by_update_url_.erase(update_url);
419 LOG(WARNING) << "Malformed Extension Management settings for "
420 "extensions with update url: " << update_url << ".";
421 }
422 } else {
423 const std::string& extension_id = iter.key();
424 if (!crx_file::id_util::IdIsValid(extension_id)) {
425 LOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
426 continue;
427 }
428 internal::IndividualSettings* by_id = AccessById(extension_id);
429 if (!by_id->Parse(subdict,
430 internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
431 settings_by_id_.erase(extension_id);
432 LOG(WARNING) << "Malformed Extension Management settings for "
433 << extension_id << ".";
434 }
binjinb2454382014-09-22 15:17:43435 }
436 }
437 }
binjin5f405ef2014-09-03 21:23:16438}
439
binjin5f405ef2014-09-03 21:23:16440const base::Value* ExtensionManagement::LoadPreference(
441 const char* pref_name,
442 bool force_managed,
443 base::Value::Type expected_type) {
binjine6b58b52014-10-31 01:55:57444 if (!pref_service_)
445 return nullptr;
binjin5f405ef2014-09-03 21:23:16446 const PrefService::Preference* pref =
447 pref_service_->FindPreference(pref_name);
448 if (pref && !pref->IsDefaultValue() &&
449 (!force_managed || pref->IsManaged())) {
450 const base::Value* value = pref->GetValue();
jdoerrie1f536b22017-10-23 17:15:11451 if (value && value->type() == expected_type)
binjin5f405ef2014-09-03 21:23:16452 return value;
453 }
binjine6b58b52014-10-31 01:55:57454 return nullptr;
binjin5f405ef2014-09-03 21:23:16455}
456
binjin1569c9b2014-09-05 13:33:18457void ExtensionManagement::OnExtensionPrefChanged() {
458 Refresh();
459 NotifyExtensionManagementPrefChanged();
460}
461
462void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
ericwilligersb5f79de2016-10-19 04:15:10463 for (auto& observer : observer_list_)
464 observer.OnExtensionManagementSettingsChanged();
binjin1569c9b2014-09-05 13:33:18465}
466
achuith4607f072017-03-08 11:49:13467std::unique_ptr<base::DictionaryValue>
468ExtensionManagement::GetInstallListByMode(
469 InstallationMode installation_mode) const {
Jinho Bangb5216cec2018-01-17 19:43:11470 auto extension_dict = std::make_unique<base::DictionaryValue>();
achuith4607f072017-03-08 11:49:13471 for (const auto& entry : settings_by_id_) {
472 if (entry.second->installation_mode == installation_mode) {
473 ExternalPolicyLoader::AddExtension(extension_dict.get(), entry.first,
474 entry.second->update_url);
475 }
476 }
477 return extension_dict;
478}
479
480void ExtensionManagement::UpdateForcedExtensions(
481 const base::DictionaryValue* extension_dict) {
482 if (!extension_dict)
483 return;
484
485 std::string update_url;
486 for (base::DictionaryValue::Iterator it(*extension_dict); !it.IsAtEnd();
487 it.Advance()) {
488 if (!crx_file::id_util::IdIsValid(it.key()))
489 continue;
490 const base::DictionaryValue* dict_value = nullptr;
491 if (it.value().GetAsDictionary(&dict_value) &&
492 dict_value->GetStringWithoutPathExpansion(
493 ExternalProviderImpl::kExternalUpdateUrl, &update_url)) {
494 internal::IndividualSettings* by_id = AccessById(it.key());
495 by_id->installation_mode = INSTALLATION_FORCED;
496 by_id->update_url = update_url;
497 }
498 }
499}
500
binjin81d7c552014-10-02 11:47:12501internal::IndividualSettings* ExtensionManagement::AccessById(
binjin5f405ef2014-09-03 21:23:16502 const ExtensionId& id) {
503 DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id;
avi3ec9c0d2016-12-27 22:38:06504 std::unique_ptr<internal::IndividualSettings>& settings = settings_by_id_[id];
505 if (!settings) {
506 settings =
Jinho Bangb5216cec2018-01-17 19:43:11507 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin81d7c552014-10-02 11:47:12508 }
avi3ec9c0d2016-12-27 22:38:06509 return settings.get();
binjin5f405ef2014-09-03 21:23:16510}
511
binjin685ade82014-11-06 09:53:56512internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
513 const std::string& update_url) {
514 DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
avi3ec9c0d2016-12-27 22:38:06515 std::unique_ptr<internal::IndividualSettings>& settings =
516 settings_by_update_url_[update_url];
517 if (!settings) {
518 settings =
Jinho Bangb5216cec2018-01-17 19:43:11519 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin685ade82014-11-06 09:53:56520 }
avi3ec9c0d2016-12-27 22:38:06521 return settings.get();
binjin685ade82014-11-06 09:53:56522}
523
binjin1569c9b2014-09-05 13:33:18524ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(
525 content::BrowserContext* context) {
526 return static_cast<ExtensionManagement*>(
527 GetInstance()->GetServiceForBrowserContext(context, true));
528}
529
530ExtensionManagementFactory* ExtensionManagementFactory::GetInstance() {
olli.raula36aa8be2015-09-10 11:14:22531 return base::Singleton<ExtensionManagementFactory>::get();
binjin1569c9b2014-09-05 13:33:18532}
533
534ExtensionManagementFactory::ExtensionManagementFactory()
535 : BrowserContextKeyedServiceFactory(
536 "ExtensionManagement",
537 BrowserContextDependencyManager::GetInstance()) {
538}
539
540ExtensionManagementFactory::~ExtensionManagementFactory() {
541}
542
543KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor(
544 content::BrowserContext* context) const {
rkaplowdd66a1342015-03-05 00:31:49545 TRACE_EVENT0("browser,startup",
546 "ExtensionManagementFactory::BuildServiceInstanceFor");
achuith4607f072017-03-08 11:49:13547 Profile* profile = Profile::FromBrowserContext(context);
548 bool is_signin_profile = false;
549#if defined(OS_CHROMEOS)
550 is_signin_profile = chromeos::ProfileHelper::IsSigninProfile(profile);
551#endif
552 return new ExtensionManagement(profile->GetPrefs(), is_signin_profile);
binjin1569c9b2014-09-05 13:33:18553}
554
binjin9733df12014-09-08 15:21:21555content::BrowserContext* ExtensionManagementFactory::GetBrowserContextToUse(
556 content::BrowserContext* context) const {
557 return chrome::GetBrowserContextRedirectedInIncognito(context);
558}
559
binjinb2454382014-09-22 15:17:43560void ExtensionManagementFactory::RegisterProfilePrefs(
561 user_prefs::PrefRegistrySyncable* user_prefs) {
raymesaa608722015-04-27 03:00:25562 user_prefs->RegisterDictionaryPref(pref_names::kExtensionManagement);
binjinb2454382014-09-22 15:17:43563}
564
binjin5f405ef2014-09-03 21:23:16565} // namespace extensions