blob: a51e03c7ab8c158cca518c9a40e3cbc7e943df5e [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"
Sergey Poromov296de0a2018-10-11 21:44:0822#include "chrome/browser/extensions/forced_extensions/installation_failures.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"
Owen Mina9a13e12018-11-01 20:43:5227#include "chrome/common/extensions/extension_constants.h"
28#include "chrome/common/pref_names.h"
binjin5f405ef2014-09-03 21:23:1629#include "components/crx_file/id_util.h"
binjin1569c9b2014-09-05 13:33:1830#include "components/keyed_service/content/browser_context_dependency_manager.h"
binjinb2454382014-09-22 15:17:4331#include "components/pref_registry/pref_registry_syncable.h"
brettwb1fc1b82016-02-02 00:19:0832#include "components/prefs/pref_service.h"
binjin5f405ef2014-09-03 21:23:1633#include "extensions/browser/pref_names.h"
rdevlin.cronin0670b562016-07-02 02:05:4334#include "extensions/common/extension.h"
Owen Mina9a13e12018-11-01 20:43:5235#include "extensions/common/extension_urls.h"
binjin685ade82014-11-06 09:53:5636#include "extensions/common/manifest_constants.h"
binjine6b58b52014-10-31 01:55:5737#include "extensions/common/permissions/api_permission_set.h"
38#include "extensions/common/permissions/permission_set.h"
binjin5f405ef2014-09-03 21:23:1639#include "extensions/common/url_pattern.h"
binjin311ecdf2014-09-12 22:56:5240#include "url/gurl.h"
binjin5f405ef2014-09-03 21:23:1641
achuith4607f072017-03-08 11:49:1342#if defined(OS_CHROMEOS)
43#include "chrome/browser/chromeos/profiles/profile_helper.h"
44#endif
45
binjin5f405ef2014-09-03 21:23:1646namespace extensions {
47
Sergey Poromov741e70702018-10-11 20:11:5448ExtensionManagement::ExtensionManagement(Profile* profile)
49 : profile_(profile), pref_service_(profile_->GetPrefs()) {
rkaplowdd66a1342015-03-05 00:31:4950 TRACE_EVENT0("browser,startup",
51 "ExtensionManagement::ExtensionManagement::ctor");
Sergey Poromov741e70702018-10-11 20:11:5452#if defined(OS_CHROMEOS)
53 is_signin_profile_ = chromeos::ProfileHelper::IsSigninProfile(profile);
54#endif
binjin1569c9b2014-09-05 13:33:1855 pref_change_registrar_.Init(pref_service_);
56 base::Closure pref_change_callback = base::Bind(
57 &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this));
58 pref_change_registrar_.Add(pref_names::kInstallAllowList,
59 pref_change_callback);
60 pref_change_registrar_.Add(pref_names::kInstallDenyList,
61 pref_change_callback);
62 pref_change_registrar_.Add(pref_names::kInstallForceList,
63 pref_change_callback);
Alexander Hendrichb07fd55b2019-04-01 09:24:3764 pref_change_registrar_.Add(pref_names::kLoginScreenExtensions,
achuith4607f072017-03-08 11:49:1365 pref_change_callback);
binjin1569c9b2014-09-05 13:33:1866 pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
67 pref_change_callback);
68 pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
binjinb2454382014-09-22 15:17:4369 pref_change_registrar_.Add(pref_names::kExtensionManagement,
70 pref_change_callback);
Owen Mina9a13e12018-11-01 20:43:5271#if !defined(OS_CHROMEOS)
72 pref_change_registrar_.Add(prefs::kCloudReportingEnabled,
73 pref_change_callback);
74#endif
binjin81d7c552014-10-02 11:47:1275 // Note that both |global_settings_| and |default_settings_| will be null
76 // before first call to Refresh(), so in order to resolve this, Refresh() must
77 // be called in the initialization of ExtensionManagement.
binjin1569c9b2014-09-05 13:33:1878 Refresh();
lazyboy4aeef202016-09-07 21:28:5979 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1180 std::make_unique<StandardManagementPolicyProvider>(this));
lazyboy4aeef202016-09-07 21:28:5981 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1182 std::make_unique<PermissionsBasedManagementPolicyProvider>(this));
binjin5f405ef2014-09-03 21:23:1683}
84
85ExtensionManagement::~ExtensionManagement() {
86}
87
binjine6b58b52014-10-31 01:55:5788void ExtensionManagement::Shutdown() {
89 pref_change_registrar_.RemoveAll();
90 pref_service_ = nullptr;
91}
92
binjin1569c9b2014-09-05 13:33:1893void ExtensionManagement::AddObserver(Observer* observer) {
94 observer_list_.AddObserver(observer);
95}
96
97void ExtensionManagement::RemoveObserver(Observer* observer) {
98 observer_list_.RemoveObserver(observer);
99}
100
lazyboy4aeef202016-09-07 21:28:59101const std::vector<std::unique_ptr<ManagementPolicy::Provider>>&
102ExtensionManagement::GetProviders() const {
103 return providers_;
binjin1569c9b2014-09-05 13:33:18104}
105
binjin81d7c552014-10-02 11:47:12106bool ExtensionManagement::BlacklistedByDefault() const {
107 return default_settings_->installation_mode == INSTALLATION_BLOCKED;
108}
109
110ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
binjin685ade82014-11-06 09:53:56111 const Extension* extension) const {
112 // Check per-extension installation mode setting first.
113 auto iter_id = settings_by_id_.find(extension->id());
114 if (iter_id != settings_by_id_.end())
115 return iter_id->second->installation_mode;
116 std::string update_url;
117 // Check per-update-url installation mode setting.
118 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
119 &update_url)) {
120 auto iter_update_url = settings_by_update_url_.find(update_url);
121 if (iter_update_url != settings_by_update_url_.end())
122 return iter_update_url->second->installation_mode;
123 }
124 // Fall back to default installation mode setting.
125 return default_settings_->installation_mode;
binjin1569c9b2014-09-05 13:33:18126}
127
dchengc963c7142016-04-08 03:55:22128std::unique_ptr<base::DictionaryValue>
hashimoto146e05a2016-11-18 07:42:53129ExtensionManagement::GetForceInstallList() const {
achuith4607f072017-03-08 11:49:13130 return GetInstallListByMode(INSTALLATION_FORCED);
binjincccacef2014-10-13 19:00:20131}
132
dchengc963c7142016-04-08 03:55:22133std::unique_ptr<base::DictionaryValue>
binjincccacef2014-10-13 19:00:20134ExtensionManagement::GetRecommendedInstallList() const {
achuith4607f072017-03-08 11:49:13135 return GetInstallListByMode(INSTALLATION_RECOMMENDED);
binjin30301062014-09-08 20:27:34136}
137
Yann Dago726278c62019-03-18 14:59:55138bool ExtensionManagement::HasWhitelistedExtension() const {
139 if (default_settings_->installation_mode != INSTALLATION_BLOCKED)
140 return true;
141
142 for (const auto& it : settings_by_id_) {
143 if (it.second->installation_mode == INSTALLATION_ALLOWED)
144 return true;
145 }
146 return false;
147}
148
binjinc641add2014-10-15 16:20:45149bool ExtensionManagement::IsInstallationExplicitlyAllowed(
150 const ExtensionId& id) const {
avi3ec9c0d2016-12-27 22:38:06151 auto it = settings_by_id_.find(id);
binjinc641add2014-10-15 16:20:45152 // No settings explicitly specified for |id|.
153 if (it == settings_by_id_.end())
154 return false;
155 // Checks if the extension is on the automatically installed list or
156 // install white-list.
157 InstallationMode mode = it->second->installation_mode;
158 return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
159 mode == INSTALLATION_ALLOWED;
binjin30301062014-09-08 20:27:34160}
161
binjin81d7c552014-10-02 11:47:12162bool ExtensionManagement::IsOffstoreInstallAllowed(
163 const GURL& url,
164 const GURL& referrer_url) const {
binjin311ecdf2014-09-12 22:56:52165 // No allowed install sites specified, disallow by default.
binjin81d7c552014-10-02 11:47:12166 if (!global_settings_->has_restricted_install_sources)
binjin311ecdf2014-09-12 22:56:52167 return false;
168
binjin81d7c552014-10-02 11:47:12169 const URLPatternSet& url_patterns = global_settings_->install_sources;
binjin311ecdf2014-09-12 22:56:52170
171 if (!url_patterns.MatchesURL(url))
172 return false;
173
174 // The referrer URL must also be whitelisted, unless the URL has the file
175 // scheme (there's no referrer for those URLs).
176 return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url);
177}
178
binjin81d7c552014-10-02 11:47:12179bool ExtensionManagement::IsAllowedManifestType(
Owen Mina9a13e12018-11-01 20:43:52180 Manifest::Type manifest_type,
181 const std::string& extension_id) const {
182 if (extension_id == extension_misc::kCloudReportingExtensionId &&
183 IsCloudReportingPolicyEnabled()) {
184 return true;
185 }
186
binjin81d7c552014-10-02 11:47:12187 if (!global_settings_->has_restricted_allowed_types)
188 return true;
189 const std::vector<Manifest::Type>& allowed_types =
190 global_settings_->allowed_types;
tripta.g0ac673a2017-07-07 05:45:09191 return base::ContainsValue(allowed_types, manifest_type);
binjin1569c9b2014-09-05 13:33:18192}
193
binjin685ade82014-11-06 09:53:56194APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
195 const Extension* extension) const {
Owen Mina9a13e12018-11-01 20:43:52196 // The Chrome Reporting extension is sideloaded via the CloudReportingEnabled
197 // policy and is not subject to permission withholding.
198 if (extension->id() == extension_misc::kCloudReportingExtensionId &&
199 IsCloudReportingPolicyEnabled()) {
200 return APIPermissionSet();
201 }
202
binjin685ade82014-11-06 09:53:56203 // Fetch per-extension blocked permissions setting.
204 auto iter_id = settings_by_id_.find(extension->id());
205
206 // Fetch per-update-url blocked permissions setting.
207 std::string update_url;
208 auto iter_update_url = settings_by_update_url_.end();
209 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
210 &update_url)) {
211 iter_update_url = settings_by_update_url_.find(update_url);
212 }
213
214 if (iter_id != settings_by_id_.end() &&
215 iter_update_url != settings_by_update_url_.end()) {
216 // Blocked permissions setting are specified in both per-extension and
217 // per-update-url settings, try to merge them.
218 APIPermissionSet merged;
219 APIPermissionSet::Union(iter_id->second->blocked_permissions,
220 iter_update_url->second->blocked_permissions,
221 &merged);
222 return merged;
223 }
224 // Check whether if in one of them, setting is specified.
225 if (iter_id != settings_by_id_.end())
Devlin Cronin32708b02018-12-05 17:58:04226 return iter_id->second->blocked_permissions.Clone();
binjin685ade82014-11-06 09:53:56227 if (iter_update_url != settings_by_update_url_.end())
Devlin Cronin32708b02018-12-05 17:58:04228 return iter_update_url->second->blocked_permissions.Clone();
binjin685ade82014-11-06 09:53:56229 // Fall back to the default blocked permissions setting.
Devlin Cronin32708b02018-12-05 17:58:04230 return default_settings_->blocked_permissions.Clone();
binjine6b58b52014-10-31 01:55:57231}
232
Devlin Cronin7e0f41ff2018-05-16 17:19:36233const URLPatternSet& ExtensionManagement::GetDefaultPolicyBlockedHosts() const {
234 return default_settings_->policy_blocked_hosts;
nrpetere33d2a5b2017-04-25 00:12:31235}
236
Devlin Cronin7e0f41ff2018-05-16 17:19:36237const URLPatternSet& ExtensionManagement::GetDefaultPolicyAllowedHosts() const {
238 return default_settings_->policy_allowed_hosts;
nrpetere33d2a5b2017-04-25 00:12:31239}
240
Devlin Cronin7e0f41ff2018-05-16 17:19:36241const URLPatternSet& ExtensionManagement::GetPolicyBlockedHosts(
nrpeter40e16382017-04-13 17:34:58242 const Extension* extension) const {
243 auto iter_id = settings_by_id_.find(extension->id());
244 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36245 return iter_id->second->policy_blocked_hosts;
246 return default_settings_->policy_blocked_hosts;
nrpeter40e16382017-04-13 17:34:58247}
248
Devlin Cronin7e0f41ff2018-05-16 17:19:36249const URLPatternSet& ExtensionManagement::GetPolicyAllowedHosts(
nrpeter40e16382017-04-13 17:34:58250 const Extension* extension) const {
251 auto iter_id = settings_by_id_.find(extension->id());
252 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36253 return iter_id->second->policy_allowed_hosts;
254 return default_settings_->policy_allowed_hosts;
nrpeter40e16382017-04-13 17:34:58255}
256
Devlin Cronin7e0f41ff2018-05-16 17:19:36257bool ExtensionManagement::UsesDefaultPolicyHostRestrictions(
nrpetere33d2a5b2017-04-25 00:12:31258 const Extension* extension) const {
259 return settings_by_id_.find(extension->id()) == settings_by_id_.end();
260}
261
Devlin Cronin7e0f41ff2018-05-16 17:19:36262bool ExtensionManagement::IsPolicyBlockedHost(const Extension* extension,
263 const GURL& url) const {
nrpeter40e16382017-04-13 17:34:58264 auto iter_id = settings_by_id_.find(extension->id());
265 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36266 return iter_id->second->policy_blocked_hosts.MatchesURL(url);
267 return default_settings_->policy_blocked_hosts.MatchesURL(url);
nrpeter40e16382017-04-13 17:34:58268}
269
dchengc963c7142016-04-08 03:55:22270std::unique_ptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
binjin685ade82014-11-06 09:53:56271 const Extension* extension) const {
binjine6b58b52014-10-31 01:55:57272 // Only api permissions are supported currently.
dchengc963c7142016-04-08 03:55:22273 return std::unique_ptr<const PermissionSet>(new PermissionSet(
binjin685ade82014-11-06 09:53:56274 GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
275 URLPatternSet(), URLPatternSet()));
binjine6b58b52014-10-31 01:55:57276}
277
278bool ExtensionManagement::IsPermissionSetAllowed(
binjin685ade82014-11-06 09:53:56279 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:49280 const PermissionSet& perms) const {
vmpstrae72b082016-07-25 21:55:47281 for (auto* blocked_api : GetBlockedAPIPermissions(extension)) {
rdevlin.cronine2d0fd02015-09-24 22:35:49282 if (perms.HasAPIPermission(blocked_api->id()))
binjine6b58b52014-10-31 01:55:57283 return false;
284 }
285 return true;
286}
287
nrpeter2362e7e2017-05-10 17:21:26288const std::string ExtensionManagement::BlockedInstallMessage(
289 const ExtensionId& id) const {
290 auto iter_id = settings_by_id_.find(id);
291 if (iter_id != settings_by_id_.end())
292 return iter_id->second->blocked_install_message;
293 return default_settings_->blocked_install_message;
294}
295
binjin8e3d0182014-12-04 16:44:28296bool ExtensionManagement::CheckMinimumVersion(
297 const Extension* extension,
298 std::string* required_version) const {
299 auto iter = settings_by_id_.find(extension->id());
300 // If there are no minimum version required for |extension|, return true.
301 if (iter == settings_by_id_.end() || !iter->second->minimum_version_required)
302 return true;
Devlin Cronin03bf2d22017-12-20 08:21:05303 bool meets_requirement = extension->version().CompareTo(
304 *iter->second->minimum_version_required) >= 0;
binjin8e3d0182014-12-04 16:44:28305 // Output a human readable version string for prompting if necessary.
306 if (!meets_requirement && required_version)
307 *required_version = iter->second->minimum_version_required->GetString();
308 return meets_requirement;
309}
310
binjin5f405ef2014-09-03 21:23:16311void ExtensionManagement::Refresh() {
rkaplowdd66a1342015-03-05 00:31:49312 TRACE_EVENT0("browser,startup", "ExtensionManagement::Refresh");
313 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ExtensionManagement_RefreshTime");
binjin5f405ef2014-09-03 21:23:16314 // Load all extension management settings preferences.
315 const base::ListValue* allowed_list_pref =
316 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28317 pref_names::kInstallAllowList, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16318 // Allow user to use preference to block certain extensions. Note that policy
319 // managed forcelist or whitelist will always override this.
320 const base::ListValue* denied_list_pref =
321 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28322 pref_names::kInstallDenyList, false, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16323 const base::DictionaryValue* forced_list_pref =
324 static_cast<const base::DictionaryValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28325 pref_names::kInstallForceList, true, base::Value::Type::DICTIONARY));
Alexander Hendrichb07fd55b2019-04-01 09:24:37326 const base::DictionaryValue* login_screen_extensions_pref = nullptr;
achuith4607f072017-03-08 11:49:13327 if (is_signin_profile_) {
Alexander Hendrichb07fd55b2019-04-01 09:24:37328 login_screen_extensions_pref = static_cast<const base::DictionaryValue*>(
329 LoadPreference(pref_names::kLoginScreenExtensions, true,
achuith4607f072017-03-08 11:49:13330 base::Value::Type::DICTIONARY));
331 }
binjin5f405ef2014-09-03 21:23:16332 const base::ListValue* install_sources_pref =
333 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28334 pref_names::kAllowedInstallSites, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16335 const base::ListValue* allowed_types_pref =
336 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28337 pref_names::kAllowedTypes, true, base::Value::Type::LIST));
binjinb2454382014-09-22 15:17:43338 const base::DictionaryValue* dict_pref =
339 static_cast<const base::DictionaryValue*>(
340 LoadPreference(pref_names::kExtensionManagement,
341 true,
jdoerriedc72ee942016-12-07 15:43:28342 base::Value::Type::DICTIONARY));
binjin5f405ef2014-09-03 21:23:16343
344 // Reset all settings.
binjin81d7c552014-10-02 11:47:12345 global_settings_.reset(new internal::GlobalSettings());
binjin5f405ef2014-09-03 21:23:16346 settings_by_id_.clear();
binjin81d7c552014-10-02 11:47:12347 default_settings_.reset(new internal::IndividualSettings());
binjin5f405ef2014-09-03 21:23:16348
349 // Parse default settings.
jdoerrie122c4da2017-03-06 11:12:04350 const base::Value wildcard("*");
binjin5f405ef2014-09-03 21:23:16351 if (denied_list_pref &&
352 denied_list_pref->Find(wildcard) != denied_list_pref->end()) {
binjin81d7c552014-10-02 11:47:12353 default_settings_->installation_mode = INSTALLATION_BLOCKED;
binjin5f405ef2014-09-03 21:23:16354 }
355
binjinb2454382014-09-22 15:17:43356 const base::DictionaryValue* subdict = NULL;
357 if (dict_pref &&
358 dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) {
binjin81d7c552014-10-02 11:47:12359 if (!default_settings_->Parse(
360 subdict, internal::IndividualSettings::SCOPE_DEFAULT)) {
binjinb2454382014-09-22 15:17:43361 LOG(WARNING) << "Default extension management settings parsing error.";
binjin81d7c552014-10-02 11:47:12362 default_settings_->Reset();
binjinb2454382014-09-22 15:17:43363 }
364
365 // Settings from new preference have higher priority over legacy ones.
366 const base::ListValue* list_value = NULL;
367 if (subdict->GetList(schema_constants::kInstallSources, &list_value))
368 install_sources_pref = list_value;
369 if (subdict->GetList(schema_constants::kAllowedTypes, &list_value))
370 allowed_types_pref = list_value;
371 }
372
binjin5f405ef2014-09-03 21:23:16373 // Parse legacy preferences.
374 ExtensionId id;
375
376 if (allowed_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02377 for (auto it = allowed_list_pref->begin(); it != allowed_list_pref->end();
378 ++it) {
jdoerriea5676c62017-04-11 18:09:14379 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16380 AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
381 }
382 }
383
384 if (denied_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02385 for (auto it = denied_list_pref->begin(); it != denied_list_pref->end();
386 ++it) {
jdoerriea5676c62017-04-11 18:09:14387 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16388 AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
389 }
390 }
391
achuith4607f072017-03-08 11:49:13392 UpdateForcedExtensions(forced_list_pref);
Alexander Hendrichb07fd55b2019-04-01 09:24:37393 UpdateForcedExtensions(login_screen_extensions_pref);
binjin5f405ef2014-09-03 21:23:16394
395 if (install_sources_pref) {
binjin81d7c552014-10-02 11:47:12396 global_settings_->has_restricted_install_sources = true;
jdoerrie13cd648c82018-10-02 21:21:02397 for (auto it = install_sources_pref->begin();
binjin5f405ef2014-09-03 21:23:16398 it != install_sources_pref->end(); ++it) {
binjinb2454382014-09-22 15:17:43399 std::string url_pattern;
jdoerriea5676c62017-04-11 18:09:14400 if (it->GetAsString(&url_pattern)) {
binjinb2454382014-09-22 15:17:43401 URLPattern entry(URLPattern::SCHEME_ALL);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18402 if (entry.Parse(url_pattern) == URLPattern::ParseResult::kSuccess) {
binjin81d7c552014-10-02 11:47:12403 global_settings_->install_sources.AddPattern(entry);
binjin5f405ef2014-09-03 21:23:16404 } else {
405 LOG(WARNING) << "Invalid URL pattern in for preference "
406 << pref_names::kAllowedInstallSites << ": "
407 << url_pattern << ".";
408 }
409 }
410 }
411 }
412
413 if (allowed_types_pref) {
binjin81d7c552014-10-02 11:47:12414 global_settings_->has_restricted_allowed_types = true;
jdoerrie13cd648c82018-10-02 21:21:02415 for (auto it = allowed_types_pref->begin(); it != allowed_types_pref->end();
416 ++it) {
binjin5f405ef2014-09-03 21:23:16417 int int_value;
binjinb2454382014-09-22 15:17:43418 std::string string_value;
jdoerriea5676c62017-04-11 18:09:14419 if (it->GetAsInteger(&int_value) && int_value >= 0 &&
binjin5f405ef2014-09-03 21:23:16420 int_value < Manifest::Type::NUM_LOAD_TYPES) {
binjin81d7c552014-10-02 11:47:12421 global_settings_->allowed_types.push_back(
binjin5f405ef2014-09-03 21:23:16422 static_cast<Manifest::Type>(int_value));
jdoerriea5676c62017-04-11 18:09:14423 } else if (it->GetAsString(&string_value)) {
binjinb2454382014-09-22 15:17:43424 Manifest::Type manifest_type =
425 schema_constants::GetManifestType(string_value);
426 if (manifest_type != Manifest::TYPE_UNKNOWN)
binjin81d7c552014-10-02 11:47:12427 global_settings_->allowed_types.push_back(manifest_type);
binjin5f405ef2014-09-03 21:23:16428 }
429 }
430 }
431
binjinb2454382014-09-22 15:17:43432 if (dict_pref) {
433 // Parse new extension management preference.
434 for (base::DictionaryValue::Iterator iter(*dict_pref); !iter.IsAtEnd();
435 iter.Advance()) {
436 if (iter.key() == schema_constants::kWildcard)
437 continue;
binjin81d7c552014-10-02 11:47:12438 if (!iter.value().GetAsDictionary(&subdict))
binjinb2454382014-09-22 15:17:43439 continue;
brettw66d1b81b2015-07-06 19:29:40440 if (base::StartsWith(iter.key(), schema_constants::kUpdateUrlPrefix,
441 base::CompareCase::SENSITIVE)) {
binjin685ade82014-11-06 09:53:56442 const std::string& update_url =
443 iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
444 if (!GURL(update_url).is_valid()) {
445 LOG(WARNING) << "Invalid update URL: " << update_url << ".";
446 continue;
447 }
448 internal::IndividualSettings* by_update_url =
449 AccessByUpdateUrl(update_url);
450 if (!by_update_url->Parse(
451 subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
452 settings_by_update_url_.erase(update_url);
453 LOG(WARNING) << "Malformed Extension Management settings for "
454 "extensions with update url: " << update_url << ".";
455 }
456 } else {
457 const std::string& extension_id = iter.key();
458 if (!crx_file::id_util::IdIsValid(extension_id)) {
459 LOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
460 continue;
461 }
462 internal::IndividualSettings* by_id = AccessById(extension_id);
463 if (!by_id->Parse(subdict,
464 internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
465 settings_by_id_.erase(extension_id);
Sergey Poromov296de0a2018-10-11 21:44:08466 InstallationFailures::ReportFailure(
467 profile_, extension_id,
468 InstallationFailures::Reason::MALFORMED_EXTENSION_SETTINGS);
binjin685ade82014-11-06 09:53:56469 LOG(WARNING) << "Malformed Extension Management settings for "
470 << extension_id << ".";
471 }
binjinb2454382014-09-22 15:17:43472 }
473 }
474 }
Owen Mina9a13e12018-11-01 20:43:52475
476 UpdateForcedCloudReportingExtension();
binjin5f405ef2014-09-03 21:23:16477}
478
binjin5f405ef2014-09-03 21:23:16479const base::Value* ExtensionManagement::LoadPreference(
480 const char* pref_name,
481 bool force_managed,
Owen Mina9a13e12018-11-01 20:43:52482 base::Value::Type expected_type) const {
binjine6b58b52014-10-31 01:55:57483 if (!pref_service_)
484 return nullptr;
binjin5f405ef2014-09-03 21:23:16485 const PrefService::Preference* pref =
486 pref_service_->FindPreference(pref_name);
487 if (pref && !pref->IsDefaultValue() &&
488 (!force_managed || pref->IsManaged())) {
489 const base::Value* value = pref->GetValue();
jdoerrie1f536b22017-10-23 17:15:11490 if (value && value->type() == expected_type)
binjin5f405ef2014-09-03 21:23:16491 return value;
492 }
binjine6b58b52014-10-31 01:55:57493 return nullptr;
binjin5f405ef2014-09-03 21:23:16494}
495
binjin1569c9b2014-09-05 13:33:18496void ExtensionManagement::OnExtensionPrefChanged() {
497 Refresh();
498 NotifyExtensionManagementPrefChanged();
499}
500
501void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
ericwilligersb5f79de2016-10-19 04:15:10502 for (auto& observer : observer_list_)
503 observer.OnExtensionManagementSettingsChanged();
binjin1569c9b2014-09-05 13:33:18504}
505
achuith4607f072017-03-08 11:49:13506std::unique_ptr<base::DictionaryValue>
507ExtensionManagement::GetInstallListByMode(
508 InstallationMode installation_mode) const {
Jinho Bangb5216cec2018-01-17 19:43:11509 auto extension_dict = std::make_unique<base::DictionaryValue>();
achuith4607f072017-03-08 11:49:13510 for (const auto& entry : settings_by_id_) {
511 if (entry.second->installation_mode == installation_mode) {
512 ExternalPolicyLoader::AddExtension(extension_dict.get(), entry.first,
513 entry.second->update_url);
514 }
515 }
516 return extension_dict;
517}
518
519void ExtensionManagement::UpdateForcedExtensions(
520 const base::DictionaryValue* extension_dict) {
521 if (!extension_dict)
522 return;
523
524 std::string update_url;
525 for (base::DictionaryValue::Iterator it(*extension_dict); !it.IsAtEnd();
526 it.Advance()) {
Sergey Poromov296de0a2018-10-11 21:44:08527 if (!crx_file::id_util::IdIsValid(it.key())) {
528 InstallationFailures::ReportFailure(
529 profile_, it.key(), InstallationFailures::Reason::INVALID_ID);
achuith4607f072017-03-08 11:49:13530 continue;
Sergey Poromov296de0a2018-10-11 21:44:08531 }
achuith4607f072017-03-08 11:49:13532 const base::DictionaryValue* dict_value = nullptr;
533 if (it.value().GetAsDictionary(&dict_value) &&
534 dict_value->GetStringWithoutPathExpansion(
535 ExternalProviderImpl::kExternalUpdateUrl, &update_url)) {
536 internal::IndividualSettings* by_id = AccessById(it.key());
537 by_id->installation_mode = INSTALLATION_FORCED;
538 by_id->update_url = update_url;
539 }
540 }
541}
542
Owen Mina9a13e12018-11-01 20:43:52543void ExtensionManagement::UpdateForcedCloudReportingExtension() {
544 if (!IsCloudReportingPolicyEnabled())
545 return;
546
547 // Adds the Chrome Reporting extension to the force install list if
548 // CloudReportingEnabled policy is set to True. Overrides any existing setting
549 // for that extension from other policies.
550 internal::IndividualSettings* settings =
551 AccessById(extension_misc::kCloudReportingExtensionId);
552 settings->Reset();
553 settings->minimum_version_required.reset();
554 settings->installation_mode = INSTALLATION_FORCED;
555 settings->update_url = extension_urls::kChromeWebstoreUpdateURL;
556}
557
558bool ExtensionManagement::IsCloudReportingPolicyEnabled() const {
559#if !defined(OS_CHROMEOS)
560 const base::Value* policy_value =
561 LoadPreference(prefs::kCloudReportingEnabled,
562 /* force_managed = */ true, base::Value::Type::BOOLEAN);
563 return policy_value && policy_value->GetBool();
564#else
565 return false;
566#endif
567}
568
binjin81d7c552014-10-02 11:47:12569internal::IndividualSettings* ExtensionManagement::AccessById(
binjin5f405ef2014-09-03 21:23:16570 const ExtensionId& id) {
571 DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id;
avi3ec9c0d2016-12-27 22:38:06572 std::unique_ptr<internal::IndividualSettings>& settings = settings_by_id_[id];
573 if (!settings) {
574 settings =
Jinho Bangb5216cec2018-01-17 19:43:11575 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin81d7c552014-10-02 11:47:12576 }
avi3ec9c0d2016-12-27 22:38:06577 return settings.get();
binjin5f405ef2014-09-03 21:23:16578}
579
binjin685ade82014-11-06 09:53:56580internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
581 const std::string& update_url) {
582 DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
avi3ec9c0d2016-12-27 22:38:06583 std::unique_ptr<internal::IndividualSettings>& settings =
584 settings_by_update_url_[update_url];
585 if (!settings) {
586 settings =
Jinho Bangb5216cec2018-01-17 19:43:11587 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin685ade82014-11-06 09:53:56588 }
avi3ec9c0d2016-12-27 22:38:06589 return settings.get();
binjin685ade82014-11-06 09:53:56590}
591
binjin1569c9b2014-09-05 13:33:18592ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(
593 content::BrowserContext* context) {
594 return static_cast<ExtensionManagement*>(
595 GetInstance()->GetServiceForBrowserContext(context, true));
596}
597
598ExtensionManagementFactory* ExtensionManagementFactory::GetInstance() {
olli.raula36aa8be2015-09-10 11:14:22599 return base::Singleton<ExtensionManagementFactory>::get();
binjin1569c9b2014-09-05 13:33:18600}
601
602ExtensionManagementFactory::ExtensionManagementFactory()
603 : BrowserContextKeyedServiceFactory(
604 "ExtensionManagement",
605 BrowserContextDependencyManager::GetInstance()) {
606}
607
608ExtensionManagementFactory::~ExtensionManagementFactory() {
609}
610
611KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor(
612 content::BrowserContext* context) const {
rkaplowdd66a1342015-03-05 00:31:49613 TRACE_EVENT0("browser,startup",
614 "ExtensionManagementFactory::BuildServiceInstanceFor");
Sergey Poromov741e70702018-10-11 20:11:54615 return new ExtensionManagement(Profile::FromBrowserContext(context));
binjin1569c9b2014-09-05 13:33:18616}
617
binjin9733df12014-09-08 15:21:21618content::BrowserContext* ExtensionManagementFactory::GetBrowserContextToUse(
619 content::BrowserContext* context) const {
620 return chrome::GetBrowserContextRedirectedInIncognito(context);
621}
622
binjinb2454382014-09-22 15:17:43623void ExtensionManagementFactory::RegisterProfilePrefs(
624 user_prefs::PrefRegistrySyncable* user_prefs) {
raymesaa608722015-04-27 03:00:25625 user_prefs->RegisterDictionaryPref(pref_names::kExtensionManagement);
binjinb2454382014-09-22 15:17:43626}
627
binjin5f405ef2014-09-03 21:23:16628} // namespace extensions