blob: 8a0c12604fff66663839c9699a6da5fda585fb93 [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"
Kyle Spiers3bc96a192019-04-11 23:43:2116#include "base/syslog_logging.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"
Oleg Davydovc00866812019-04-04 10:47:2723#include "chrome/browser/extensions/forced_extensions/installation_reporter.h"
binjine6b58b52014-10-31 01:55:5724#include "chrome/browser/extensions/permissions_based_management_policy_provider.h"
binjin1569c9b2014-09-05 13:33:1825#include "chrome/browser/extensions/standard_management_policy_provider.h"
binjin9733df12014-09-08 15:21:2126#include "chrome/browser/profiles/incognito_helpers.h"
binjin1569c9b2014-09-05 13:33:1827#include "chrome/browser/profiles/profile.h"
Owen Mina9a13e12018-11-01 20:43:5228#include "chrome/common/extensions/extension_constants.h"
29#include "chrome/common/pref_names.h"
binjin5f405ef2014-09-03 21:23:1630#include "components/crx_file/id_util.h"
binjin1569c9b2014-09-05 13:33:1831#include "components/keyed_service/content/browser_context_dependency_manager.h"
binjinb2454382014-09-22 15:17:4332#include "components/pref_registry/pref_registry_syncable.h"
brettwb1fc1b82016-02-02 00:19:0833#include "components/prefs/pref_service.h"
binjin5f405ef2014-09-03 21:23:1634#include "extensions/browser/pref_names.h"
rdevlin.cronin0670b562016-07-02 02:05:4335#include "extensions/common/extension.h"
Owen Mina9a13e12018-11-01 20:43:5236#include "extensions/common/extension_urls.h"
binjin685ade82014-11-06 09:53:5637#include "extensions/common/manifest_constants.h"
binjine6b58b52014-10-31 01:55:5738#include "extensions/common/permissions/api_permission_set.h"
39#include "extensions/common/permissions/permission_set.h"
binjin5f405ef2014-09-03 21:23:1640#include "extensions/common/url_pattern.h"
binjin311ecdf2014-09-12 22:56:5241#include "url/gurl.h"
binjin5f405ef2014-09-03 21:23:1642
achuith4607f072017-03-08 11:49:1343#if defined(OS_CHROMEOS)
44#include "chrome/browser/chromeos/profiles/profile_helper.h"
45#endif
46
binjin5f405ef2014-09-03 21:23:1647namespace extensions {
48
Sergey Poromov741e70702018-10-11 20:11:5449ExtensionManagement::ExtensionManagement(Profile* profile)
50 : profile_(profile), pref_service_(profile_->GetPrefs()) {
rkaplowdd66a1342015-03-05 00:31:4951 TRACE_EVENT0("browser,startup",
52 "ExtensionManagement::ExtensionManagement::ctor");
Sergey Poromov741e70702018-10-11 20:11:5453#if defined(OS_CHROMEOS)
54 is_signin_profile_ = chromeos::ProfileHelper::IsSigninProfile(profile);
55#endif
binjin1569c9b2014-09-05 13:33:1856 pref_change_registrar_.Init(pref_service_);
57 base::Closure pref_change_callback = base::Bind(
58 &ExtensionManagement::OnExtensionPrefChanged, base::Unretained(this));
59 pref_change_registrar_.Add(pref_names::kInstallAllowList,
60 pref_change_callback);
61 pref_change_registrar_.Add(pref_names::kInstallDenyList,
62 pref_change_callback);
63 pref_change_registrar_.Add(pref_names::kInstallForceList,
64 pref_change_callback);
Alexander Hendrichb07fd55b2019-04-01 09:24:3765 pref_change_registrar_.Add(pref_names::kLoginScreenExtensions,
achuith4607f072017-03-08 11:49:1366 pref_change_callback);
binjin1569c9b2014-09-05 13:33:1867 pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
68 pref_change_callback);
69 pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
binjinb2454382014-09-22 15:17:4370 pref_change_registrar_.Add(pref_names::kExtensionManagement,
71 pref_change_callback);
Alexander Nohe2c5402882019-04-11 21:56:3372 pref_change_registrar_.Add(pref_names::kUninstallBlacklistedExtensions,
73 pref_change_callback);
Owen Mina9a13e12018-11-01 20:43:5274#if !defined(OS_CHROMEOS)
75 pref_change_registrar_.Add(prefs::kCloudReportingEnabled,
76 pref_change_callback);
77#endif
binjin81d7c552014-10-02 11:47:1278 // Note that both |global_settings_| and |default_settings_| will be null
79 // before first call to Refresh(), so in order to resolve this, Refresh() must
80 // be called in the initialization of ExtensionManagement.
binjin1569c9b2014-09-05 13:33:1881 Refresh();
lazyboy4aeef202016-09-07 21:28:5982 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1183 std::make_unique<StandardManagementPolicyProvider>(this));
lazyboy4aeef202016-09-07 21:28:5984 providers_.push_back(
Jinho Bangb5216cec2018-01-17 19:43:1185 std::make_unique<PermissionsBasedManagementPolicyProvider>(this));
binjin5f405ef2014-09-03 21:23:1686}
87
88ExtensionManagement::~ExtensionManagement() {
89}
90
binjine6b58b52014-10-31 01:55:5791void ExtensionManagement::Shutdown() {
92 pref_change_registrar_.RemoveAll();
93 pref_service_ = nullptr;
94}
95
binjin1569c9b2014-09-05 13:33:1896void ExtensionManagement::AddObserver(Observer* observer) {
97 observer_list_.AddObserver(observer);
98}
99
100void ExtensionManagement::RemoveObserver(Observer* observer) {
101 observer_list_.RemoveObserver(observer);
102}
103
lazyboy4aeef202016-09-07 21:28:59104const std::vector<std::unique_ptr<ManagementPolicy::Provider>>&
105ExtensionManagement::GetProviders() const {
106 return providers_;
binjin1569c9b2014-09-05 13:33:18107}
108
binjin81d7c552014-10-02 11:47:12109bool ExtensionManagement::BlacklistedByDefault() const {
Kyle Spiersbb4b9f5f52019-05-02 17:17:15110 return (default_settings_->installation_mode == INSTALLATION_BLOCKED ||
111 default_settings_->installation_mode == INSTALLATION_REMOVED);
binjin81d7c552014-10-02 11:47:12112}
113
114ExtensionManagement::InstallationMode ExtensionManagement::GetInstallationMode(
binjin685ade82014-11-06 09:53:56115 const Extension* extension) const {
116 // Check per-extension installation mode setting first.
117 auto iter_id = settings_by_id_.find(extension->id());
118 if (iter_id != settings_by_id_.end())
119 return iter_id->second->installation_mode;
120 std::string update_url;
121 // Check per-update-url installation mode setting.
122 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
123 &update_url)) {
124 auto iter_update_url = settings_by_update_url_.find(update_url);
125 if (iter_update_url != settings_by_update_url_.end())
126 return iter_update_url->second->installation_mode;
127 }
128 // Fall back to default installation mode setting.
129 return default_settings_->installation_mode;
binjin1569c9b2014-09-05 13:33:18130}
131
dchengc963c7142016-04-08 03:55:22132std::unique_ptr<base::DictionaryValue>
hashimoto146e05a2016-11-18 07:42:53133ExtensionManagement::GetForceInstallList() const {
achuith4607f072017-03-08 11:49:13134 return GetInstallListByMode(INSTALLATION_FORCED);
binjincccacef2014-10-13 19:00:20135}
136
dchengc963c7142016-04-08 03:55:22137std::unique_ptr<base::DictionaryValue>
binjincccacef2014-10-13 19:00:20138ExtensionManagement::GetRecommendedInstallList() const {
achuith4607f072017-03-08 11:49:13139 return GetInstallListByMode(INSTALLATION_RECOMMENDED);
binjin30301062014-09-08 20:27:34140}
141
Yann Dago726278c62019-03-18 14:59:55142bool ExtensionManagement::HasWhitelistedExtension() const {
Kyle Spiersbb4b9f5f52019-05-02 17:17:15143 if (default_settings_->installation_mode != INSTALLATION_BLOCKED &&
144 default_settings_->installation_mode != INSTALLATION_REMOVED) {
Yann Dago726278c62019-03-18 14:59:55145 return true;
Kyle Spiersbb4b9f5f52019-05-02 17:17:15146 }
Yann Dago726278c62019-03-18 14:59:55147
148 for (const auto& it : settings_by_id_) {
149 if (it.second->installation_mode == INSTALLATION_ALLOWED)
150 return true;
151 }
152 return false;
153}
154
binjinc641add2014-10-15 16:20:45155bool ExtensionManagement::IsInstallationExplicitlyAllowed(
156 const ExtensionId& id) const {
avi3ec9c0d2016-12-27 22:38:06157 auto it = settings_by_id_.find(id);
binjinc641add2014-10-15 16:20:45158 // No settings explicitly specified for |id|.
159 if (it == settings_by_id_.end())
160 return false;
161 // Checks if the extension is on the automatically installed list or
162 // install white-list.
163 InstallationMode mode = it->second->installation_mode;
164 return mode == INSTALLATION_FORCED || mode == INSTALLATION_RECOMMENDED ||
165 mode == INSTALLATION_ALLOWED;
binjin30301062014-09-08 20:27:34166}
167
binjin81d7c552014-10-02 11:47:12168bool ExtensionManagement::IsOffstoreInstallAllowed(
169 const GURL& url,
170 const GURL& referrer_url) const {
binjin311ecdf2014-09-12 22:56:52171 // No allowed install sites specified, disallow by default.
binjin81d7c552014-10-02 11:47:12172 if (!global_settings_->has_restricted_install_sources)
binjin311ecdf2014-09-12 22:56:52173 return false;
174
binjin81d7c552014-10-02 11:47:12175 const URLPatternSet& url_patterns = global_settings_->install_sources;
binjin311ecdf2014-09-12 22:56:52176
177 if (!url_patterns.MatchesURL(url))
178 return false;
179
180 // The referrer URL must also be whitelisted, unless the URL has the file
181 // scheme (there's no referrer for those URLs).
182 return url.SchemeIsFile() || url_patterns.MatchesURL(referrer_url);
183}
184
binjin81d7c552014-10-02 11:47:12185bool ExtensionManagement::IsAllowedManifestType(
Owen Mina9a13e12018-11-01 20:43:52186 Manifest::Type manifest_type,
187 const std::string& extension_id) const {
188 if (extension_id == extension_misc::kCloudReportingExtensionId &&
189 IsCloudReportingPolicyEnabled()) {
190 return true;
191 }
192
binjin81d7c552014-10-02 11:47:12193 if (!global_settings_->has_restricted_allowed_types)
194 return true;
195 const std::vector<Manifest::Type>& allowed_types =
196 global_settings_->allowed_types;
tripta.g0ac673a2017-07-07 05:45:09197 return base::ContainsValue(allowed_types, manifest_type);
binjin1569c9b2014-09-05 13:33:18198}
199
binjin685ade82014-11-06 09:53:56200APIPermissionSet ExtensionManagement::GetBlockedAPIPermissions(
201 const Extension* extension) const {
Owen Mina9a13e12018-11-01 20:43:52202 // The Chrome Reporting extension is sideloaded via the CloudReportingEnabled
203 // policy and is not subject to permission withholding.
204 if (extension->id() == extension_misc::kCloudReportingExtensionId &&
205 IsCloudReportingPolicyEnabled()) {
206 return APIPermissionSet();
207 }
208
binjin685ade82014-11-06 09:53:56209 // Fetch per-extension blocked permissions setting.
210 auto iter_id = settings_by_id_.find(extension->id());
211
212 // Fetch per-update-url blocked permissions setting.
213 std::string update_url;
214 auto iter_update_url = settings_by_update_url_.end();
215 if (extension->manifest()->GetString(manifest_keys::kUpdateURL,
216 &update_url)) {
217 iter_update_url = settings_by_update_url_.find(update_url);
218 }
219
220 if (iter_id != settings_by_id_.end() &&
221 iter_update_url != settings_by_update_url_.end()) {
222 // Blocked permissions setting are specified in both per-extension and
223 // per-update-url settings, try to merge them.
224 APIPermissionSet merged;
225 APIPermissionSet::Union(iter_id->second->blocked_permissions,
226 iter_update_url->second->blocked_permissions,
227 &merged);
228 return merged;
229 }
230 // Check whether if in one of them, setting is specified.
231 if (iter_id != settings_by_id_.end())
Devlin Cronin32708b02018-12-05 17:58:04232 return iter_id->second->blocked_permissions.Clone();
binjin685ade82014-11-06 09:53:56233 if (iter_update_url != settings_by_update_url_.end())
Devlin Cronin32708b02018-12-05 17:58:04234 return iter_update_url->second->blocked_permissions.Clone();
binjin685ade82014-11-06 09:53:56235 // Fall back to the default blocked permissions setting.
Devlin Cronin32708b02018-12-05 17:58:04236 return default_settings_->blocked_permissions.Clone();
binjine6b58b52014-10-31 01:55:57237}
238
Devlin Cronin7e0f41ff2018-05-16 17:19:36239const URLPatternSet& ExtensionManagement::GetDefaultPolicyBlockedHosts() const {
240 return default_settings_->policy_blocked_hosts;
nrpetere33d2a5b2017-04-25 00:12:31241}
242
Devlin Cronin7e0f41ff2018-05-16 17:19:36243const URLPatternSet& ExtensionManagement::GetDefaultPolicyAllowedHosts() const {
244 return default_settings_->policy_allowed_hosts;
nrpetere33d2a5b2017-04-25 00:12:31245}
246
Devlin Cronin7e0f41ff2018-05-16 17:19:36247const URLPatternSet& ExtensionManagement::GetPolicyBlockedHosts(
nrpeter40e16382017-04-13 17:34:58248 const Extension* extension) const {
249 auto iter_id = settings_by_id_.find(extension->id());
250 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36251 return iter_id->second->policy_blocked_hosts;
252 return default_settings_->policy_blocked_hosts;
nrpeter40e16382017-04-13 17:34:58253}
254
Devlin Cronin7e0f41ff2018-05-16 17:19:36255const URLPatternSet& ExtensionManagement::GetPolicyAllowedHosts(
nrpeter40e16382017-04-13 17:34:58256 const Extension* extension) const {
257 auto iter_id = settings_by_id_.find(extension->id());
258 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36259 return iter_id->second->policy_allowed_hosts;
260 return default_settings_->policy_allowed_hosts;
nrpeter40e16382017-04-13 17:34:58261}
262
Devlin Cronin7e0f41ff2018-05-16 17:19:36263bool ExtensionManagement::UsesDefaultPolicyHostRestrictions(
nrpetere33d2a5b2017-04-25 00:12:31264 const Extension* extension) const {
265 return settings_by_id_.find(extension->id()) == settings_by_id_.end();
266}
267
Devlin Cronin7e0f41ff2018-05-16 17:19:36268bool ExtensionManagement::IsPolicyBlockedHost(const Extension* extension,
269 const GURL& url) const {
nrpeter40e16382017-04-13 17:34:58270 auto iter_id = settings_by_id_.find(extension->id());
271 if (iter_id != settings_by_id_.end())
Devlin Cronin7e0f41ff2018-05-16 17:19:36272 return iter_id->second->policy_blocked_hosts.MatchesURL(url);
273 return default_settings_->policy_blocked_hosts.MatchesURL(url);
nrpeter40e16382017-04-13 17:34:58274}
275
dchengc963c7142016-04-08 03:55:22276std::unique_ptr<const PermissionSet> ExtensionManagement::GetBlockedPermissions(
binjin685ade82014-11-06 09:53:56277 const Extension* extension) const {
binjine6b58b52014-10-31 01:55:57278 // Only api permissions are supported currently.
dchengc963c7142016-04-08 03:55:22279 return std::unique_ptr<const PermissionSet>(new PermissionSet(
binjin685ade82014-11-06 09:53:56280 GetBlockedAPIPermissions(extension), ManifestPermissionSet(),
281 URLPatternSet(), URLPatternSet()));
binjine6b58b52014-10-31 01:55:57282}
283
284bool ExtensionManagement::IsPermissionSetAllowed(
binjin685ade82014-11-06 09:53:56285 const Extension* extension,
rdevlin.cronine2d0fd02015-09-24 22:35:49286 const PermissionSet& perms) const {
vmpstrae72b082016-07-25 21:55:47287 for (auto* blocked_api : GetBlockedAPIPermissions(extension)) {
rdevlin.cronine2d0fd02015-09-24 22:35:49288 if (perms.HasAPIPermission(blocked_api->id()))
binjine6b58b52014-10-31 01:55:57289 return false;
290 }
291 return true;
292}
293
nrpeter2362e7e2017-05-10 17:21:26294const std::string ExtensionManagement::BlockedInstallMessage(
295 const ExtensionId& id) const {
296 auto iter_id = settings_by_id_.find(id);
297 if (iter_id != settings_by_id_.end())
298 return iter_id->second->blocked_install_message;
299 return default_settings_->blocked_install_message;
300}
301
binjin8e3d0182014-12-04 16:44:28302bool ExtensionManagement::CheckMinimumVersion(
303 const Extension* extension,
304 std::string* required_version) const {
305 auto iter = settings_by_id_.find(extension->id());
306 // If there are no minimum version required for |extension|, return true.
307 if (iter == settings_by_id_.end() || !iter->second->minimum_version_required)
308 return true;
Devlin Cronin03bf2d22017-12-20 08:21:05309 bool meets_requirement = extension->version().CompareTo(
310 *iter->second->minimum_version_required) >= 0;
binjin8e3d0182014-12-04 16:44:28311 // Output a human readable version string for prompting if necessary.
312 if (!meets_requirement && required_version)
313 *required_version = iter->second->minimum_version_required->GetString();
314 return meets_requirement;
315}
316
Alexander Nohe2c5402882019-04-11 21:56:33317bool ExtensionManagement::ShouldUninstallPolicyBlacklistedExtensions() const {
318 return pref_service_->GetBoolean(pref_names::kUninstallBlacklistedExtensions);
319}
320
binjin5f405ef2014-09-03 21:23:16321void ExtensionManagement::Refresh() {
rkaplowdd66a1342015-03-05 00:31:49322 TRACE_EVENT0("browser,startup", "ExtensionManagement::Refresh");
323 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ExtensionManagement_RefreshTime");
binjin5f405ef2014-09-03 21:23:16324 // Load all extension management settings preferences.
325 const base::ListValue* allowed_list_pref =
326 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28327 pref_names::kInstallAllowList, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16328 // Allow user to use preference to block certain extensions. Note that policy
329 // managed forcelist or whitelist will always override this.
330 const base::ListValue* denied_list_pref =
331 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28332 pref_names::kInstallDenyList, false, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16333 const base::DictionaryValue* forced_list_pref =
334 static_cast<const base::DictionaryValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28335 pref_names::kInstallForceList, true, base::Value::Type::DICTIONARY));
Alexander Hendrichb07fd55b2019-04-01 09:24:37336 const base::DictionaryValue* login_screen_extensions_pref = nullptr;
achuith4607f072017-03-08 11:49:13337 if (is_signin_profile_) {
Alexander Hendrichb07fd55b2019-04-01 09:24:37338 login_screen_extensions_pref = static_cast<const base::DictionaryValue*>(
339 LoadPreference(pref_names::kLoginScreenExtensions, true,
achuith4607f072017-03-08 11:49:13340 base::Value::Type::DICTIONARY));
341 }
binjin5f405ef2014-09-03 21:23:16342 const base::ListValue* install_sources_pref =
343 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28344 pref_names::kAllowedInstallSites, true, base::Value::Type::LIST));
binjin5f405ef2014-09-03 21:23:16345 const base::ListValue* allowed_types_pref =
346 static_cast<const base::ListValue*>(LoadPreference(
jdoerriedc72ee942016-12-07 15:43:28347 pref_names::kAllowedTypes, true, base::Value::Type::LIST));
binjinb2454382014-09-22 15:17:43348 const base::DictionaryValue* dict_pref =
349 static_cast<const base::DictionaryValue*>(
350 LoadPreference(pref_names::kExtensionManagement,
351 true,
jdoerriedc72ee942016-12-07 15:43:28352 base::Value::Type::DICTIONARY));
binjin5f405ef2014-09-03 21:23:16353
354 // Reset all settings.
binjin81d7c552014-10-02 11:47:12355 global_settings_.reset(new internal::GlobalSettings());
binjin5f405ef2014-09-03 21:23:16356 settings_by_id_.clear();
binjin81d7c552014-10-02 11:47:12357 default_settings_.reset(new internal::IndividualSettings());
binjin5f405ef2014-09-03 21:23:16358
359 // Parse default settings.
jdoerrie122c4da2017-03-06 11:12:04360 const base::Value wildcard("*");
binjin5f405ef2014-09-03 21:23:16361 if (denied_list_pref &&
362 denied_list_pref->Find(wildcard) != denied_list_pref->end()) {
binjin81d7c552014-10-02 11:47:12363 default_settings_->installation_mode = INSTALLATION_BLOCKED;
binjin5f405ef2014-09-03 21:23:16364 }
365
binjinb2454382014-09-22 15:17:43366 const base::DictionaryValue* subdict = NULL;
367 if (dict_pref &&
368 dict_pref->GetDictionary(schema_constants::kWildcard, &subdict)) {
binjin81d7c552014-10-02 11:47:12369 if (!default_settings_->Parse(
370 subdict, internal::IndividualSettings::SCOPE_DEFAULT)) {
binjinb2454382014-09-22 15:17:43371 LOG(WARNING) << "Default extension management settings parsing error.";
binjin81d7c552014-10-02 11:47:12372 default_settings_->Reset();
binjinb2454382014-09-22 15:17:43373 }
374
375 // Settings from new preference have higher priority over legacy ones.
376 const base::ListValue* list_value = NULL;
377 if (subdict->GetList(schema_constants::kInstallSources, &list_value))
378 install_sources_pref = list_value;
379 if (subdict->GetList(schema_constants::kAllowedTypes, &list_value))
380 allowed_types_pref = list_value;
381 }
382
binjin5f405ef2014-09-03 21:23:16383 // Parse legacy preferences.
384 ExtensionId id;
385
386 if (allowed_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02387 for (auto it = allowed_list_pref->begin(); it != allowed_list_pref->end();
388 ++it) {
jdoerriea5676c62017-04-11 18:09:14389 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16390 AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
391 }
392 }
393
394 if (denied_list_pref) {
jdoerrie13cd648c82018-10-02 21:21:02395 for (auto it = denied_list_pref->begin(); it != denied_list_pref->end();
396 ++it) {
jdoerriea5676c62017-04-11 18:09:14397 if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
binjin5f405ef2014-09-03 21:23:16398 AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
399 }
400 }
401
achuith4607f072017-03-08 11:49:13402 UpdateForcedExtensions(forced_list_pref);
Alexander Hendrichb07fd55b2019-04-01 09:24:37403 UpdateForcedExtensions(login_screen_extensions_pref);
binjin5f405ef2014-09-03 21:23:16404
405 if (install_sources_pref) {
binjin81d7c552014-10-02 11:47:12406 global_settings_->has_restricted_install_sources = true;
jdoerrie13cd648c82018-10-02 21:21:02407 for (auto it = install_sources_pref->begin();
binjin5f405ef2014-09-03 21:23:16408 it != install_sources_pref->end(); ++it) {
binjinb2454382014-09-22 15:17:43409 std::string url_pattern;
jdoerriea5676c62017-04-11 18:09:14410 if (it->GetAsString(&url_pattern)) {
binjinb2454382014-09-22 15:17:43411 URLPattern entry(URLPattern::SCHEME_ALL);
Devlin Croninbd7f2b5fa2018-09-05 17:41:18412 if (entry.Parse(url_pattern) == URLPattern::ParseResult::kSuccess) {
binjin81d7c552014-10-02 11:47:12413 global_settings_->install_sources.AddPattern(entry);
binjin5f405ef2014-09-03 21:23:16414 } else {
415 LOG(WARNING) << "Invalid URL pattern in for preference "
416 << pref_names::kAllowedInstallSites << ": "
417 << url_pattern << ".";
418 }
419 }
420 }
421 }
422
423 if (allowed_types_pref) {
binjin81d7c552014-10-02 11:47:12424 global_settings_->has_restricted_allowed_types = true;
jdoerrie13cd648c82018-10-02 21:21:02425 for (auto it = allowed_types_pref->begin(); it != allowed_types_pref->end();
426 ++it) {
binjin5f405ef2014-09-03 21:23:16427 int int_value;
binjinb2454382014-09-22 15:17:43428 std::string string_value;
jdoerriea5676c62017-04-11 18:09:14429 if (it->GetAsInteger(&int_value) && int_value >= 0 &&
binjin5f405ef2014-09-03 21:23:16430 int_value < Manifest::Type::NUM_LOAD_TYPES) {
binjin81d7c552014-10-02 11:47:12431 global_settings_->allowed_types.push_back(
binjin5f405ef2014-09-03 21:23:16432 static_cast<Manifest::Type>(int_value));
jdoerriea5676c62017-04-11 18:09:14433 } else if (it->GetAsString(&string_value)) {
binjinb2454382014-09-22 15:17:43434 Manifest::Type manifest_type =
435 schema_constants::GetManifestType(string_value);
436 if (manifest_type != Manifest::TYPE_UNKNOWN)
binjin81d7c552014-10-02 11:47:12437 global_settings_->allowed_types.push_back(manifest_type);
binjin5f405ef2014-09-03 21:23:16438 }
439 }
440 }
441
binjinb2454382014-09-22 15:17:43442 if (dict_pref) {
443 // Parse new extension management preference.
444 for (base::DictionaryValue::Iterator iter(*dict_pref); !iter.IsAtEnd();
445 iter.Advance()) {
446 if (iter.key() == schema_constants::kWildcard)
447 continue;
binjin81d7c552014-10-02 11:47:12448 if (!iter.value().GetAsDictionary(&subdict))
binjinb2454382014-09-22 15:17:43449 continue;
brettw66d1b81b2015-07-06 19:29:40450 if (base::StartsWith(iter.key(), schema_constants::kUpdateUrlPrefix,
451 base::CompareCase::SENSITIVE)) {
binjin685ade82014-11-06 09:53:56452 const std::string& update_url =
453 iter.key().substr(strlen(schema_constants::kUpdateUrlPrefix));
454 if (!GURL(update_url).is_valid()) {
455 LOG(WARNING) << "Invalid update URL: " << update_url << ".";
456 continue;
457 }
458 internal::IndividualSettings* by_update_url =
459 AccessByUpdateUrl(update_url);
460 if (!by_update_url->Parse(
461 subdict, internal::IndividualSettings::SCOPE_UPDATE_URL)) {
462 settings_by_update_url_.erase(update_url);
463 LOG(WARNING) << "Malformed Extension Management settings for "
464 "extensions with update url: " << update_url << ".";
465 }
466 } else {
Kyle Spiers3bc96a192019-04-11 23:43:21467 std::vector<std::string> extension_ids = base::SplitString(
468 iter.key(), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
469 for (const auto& extension_id : extension_ids) {
470 if (!crx_file::id_util::IdIsValid(extension_id)) {
471 SYSLOG(WARNING) << "Invalid extension ID : " << extension_id << ".";
472 continue;
473 }
474 internal::IndividualSettings* by_id = AccessById(extension_id);
475 if (!by_id->Parse(subdict,
476 internal::IndividualSettings::SCOPE_INDIVIDUAL)) {
477 settings_by_id_.erase(extension_id);
478 InstallationReporter::ReportFailure(
479 profile_, extension_id,
480 InstallationReporter::FailureReason::
481 MALFORMED_EXTENSION_SETTINGS);
482 SYSLOG(WARNING) << "Malformed Extension Management settings for "
483 << extension_id << ".";
484 }
binjin685ade82014-11-06 09:53:56485 }
binjinb2454382014-09-22 15:17:43486 }
487 }
488 }
Owen Mina9a13e12018-11-01 20:43:52489
490 UpdateForcedCloudReportingExtension();
binjin5f405ef2014-09-03 21:23:16491}
492
binjin5f405ef2014-09-03 21:23:16493const base::Value* ExtensionManagement::LoadPreference(
494 const char* pref_name,
495 bool force_managed,
Owen Mina9a13e12018-11-01 20:43:52496 base::Value::Type expected_type) const {
binjine6b58b52014-10-31 01:55:57497 if (!pref_service_)
498 return nullptr;
binjin5f405ef2014-09-03 21:23:16499 const PrefService::Preference* pref =
500 pref_service_->FindPreference(pref_name);
501 if (pref && !pref->IsDefaultValue() &&
502 (!force_managed || pref->IsManaged())) {
503 const base::Value* value = pref->GetValue();
jdoerrie1f536b22017-10-23 17:15:11504 if (value && value->type() == expected_type)
binjin5f405ef2014-09-03 21:23:16505 return value;
506 }
binjine6b58b52014-10-31 01:55:57507 return nullptr;
binjin5f405ef2014-09-03 21:23:16508}
509
binjin1569c9b2014-09-05 13:33:18510void ExtensionManagement::OnExtensionPrefChanged() {
511 Refresh();
512 NotifyExtensionManagementPrefChanged();
513}
514
515void ExtensionManagement::NotifyExtensionManagementPrefChanged() {
ericwilligersb5f79de2016-10-19 04:15:10516 for (auto& observer : observer_list_)
517 observer.OnExtensionManagementSettingsChanged();
binjin1569c9b2014-09-05 13:33:18518}
519
achuith4607f072017-03-08 11:49:13520std::unique_ptr<base::DictionaryValue>
521ExtensionManagement::GetInstallListByMode(
522 InstallationMode installation_mode) const {
Jinho Bangb5216cec2018-01-17 19:43:11523 auto extension_dict = std::make_unique<base::DictionaryValue>();
achuith4607f072017-03-08 11:49:13524 for (const auto& entry : settings_by_id_) {
525 if (entry.second->installation_mode == installation_mode) {
526 ExternalPolicyLoader::AddExtension(extension_dict.get(), entry.first,
527 entry.second->update_url);
528 }
529 }
530 return extension_dict;
531}
532
533void ExtensionManagement::UpdateForcedExtensions(
534 const base::DictionaryValue* extension_dict) {
535 if (!extension_dict)
536 return;
537
538 std::string update_url;
539 for (base::DictionaryValue::Iterator it(*extension_dict); !it.IsAtEnd();
540 it.Advance()) {
Sergey Poromov296de0a2018-10-11 21:44:08541 if (!crx_file::id_util::IdIsValid(it.key())) {
Oleg Davydovc00866812019-04-04 10:47:27542 InstallationReporter::ReportFailure(
543 profile_, it.key(), InstallationReporter::FailureReason::INVALID_ID);
achuith4607f072017-03-08 11:49:13544 continue;
Sergey Poromov296de0a2018-10-11 21:44:08545 }
achuith4607f072017-03-08 11:49:13546 const base::DictionaryValue* dict_value = nullptr;
547 if (it.value().GetAsDictionary(&dict_value) &&
548 dict_value->GetStringWithoutPathExpansion(
549 ExternalProviderImpl::kExternalUpdateUrl, &update_url)) {
550 internal::IndividualSettings* by_id = AccessById(it.key());
551 by_id->installation_mode = INSTALLATION_FORCED;
552 by_id->update_url = update_url;
Oleg Davydovc00866812019-04-04 10:47:27553 InstallationReporter::ReportInstallationStage(
554 profile_, it.key(), InstallationReporter::Stage::CREATED);
555 } else {
556 InstallationReporter::ReportFailure(
557 profile_, it.key(),
558 InstallationReporter::FailureReason::NO_UPDATE_URL);
achuith4607f072017-03-08 11:49:13559 }
560 }
561}
562
Owen Mina9a13e12018-11-01 20:43:52563void ExtensionManagement::UpdateForcedCloudReportingExtension() {
564 if (!IsCloudReportingPolicyEnabled())
565 return;
566
567 // Adds the Chrome Reporting extension to the force install list if
568 // CloudReportingEnabled policy is set to True. Overrides any existing setting
569 // for that extension from other policies.
570 internal::IndividualSettings* settings =
571 AccessById(extension_misc::kCloudReportingExtensionId);
572 settings->Reset();
573 settings->minimum_version_required.reset();
574 settings->installation_mode = INSTALLATION_FORCED;
575 settings->update_url = extension_urls::kChromeWebstoreUpdateURL;
576}
577
578bool ExtensionManagement::IsCloudReportingPolicyEnabled() const {
579#if !defined(OS_CHROMEOS)
580 const base::Value* policy_value =
581 LoadPreference(prefs::kCloudReportingEnabled,
582 /* force_managed = */ true, base::Value::Type::BOOLEAN);
583 return policy_value && policy_value->GetBool();
584#else
585 return false;
586#endif
587}
588
binjin81d7c552014-10-02 11:47:12589internal::IndividualSettings* ExtensionManagement::AccessById(
binjin5f405ef2014-09-03 21:23:16590 const ExtensionId& id) {
591 DCHECK(crx_file::id_util::IdIsValid(id)) << "Invalid ID: " << id;
avi3ec9c0d2016-12-27 22:38:06592 std::unique_ptr<internal::IndividualSettings>& settings = settings_by_id_[id];
593 if (!settings) {
594 settings =
Jinho Bangb5216cec2018-01-17 19:43:11595 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin81d7c552014-10-02 11:47:12596 }
avi3ec9c0d2016-12-27 22:38:06597 return settings.get();
binjin5f405ef2014-09-03 21:23:16598}
599
binjin685ade82014-11-06 09:53:56600internal::IndividualSettings* ExtensionManagement::AccessByUpdateUrl(
601 const std::string& update_url) {
602 DCHECK(GURL(update_url).is_valid()) << "Invalid update URL: " << update_url;
avi3ec9c0d2016-12-27 22:38:06603 std::unique_ptr<internal::IndividualSettings>& settings =
604 settings_by_update_url_[update_url];
605 if (!settings) {
606 settings =
Jinho Bangb5216cec2018-01-17 19:43:11607 std::make_unique<internal::IndividualSettings>(default_settings_.get());
binjin685ade82014-11-06 09:53:56608 }
avi3ec9c0d2016-12-27 22:38:06609 return settings.get();
binjin685ade82014-11-06 09:53:56610}
611
binjin1569c9b2014-09-05 13:33:18612ExtensionManagement* ExtensionManagementFactory::GetForBrowserContext(
613 content::BrowserContext* context) {
614 return static_cast<ExtensionManagement*>(
615 GetInstance()->GetServiceForBrowserContext(context, true));
616}
617
618ExtensionManagementFactory* ExtensionManagementFactory::GetInstance() {
olli.raula36aa8be2015-09-10 11:14:22619 return base::Singleton<ExtensionManagementFactory>::get();
binjin1569c9b2014-09-05 13:33:18620}
621
622ExtensionManagementFactory::ExtensionManagementFactory()
623 : BrowserContextKeyedServiceFactory(
624 "ExtensionManagement",
625 BrowserContextDependencyManager::GetInstance()) {
626}
627
628ExtensionManagementFactory::~ExtensionManagementFactory() {
629}
630
631KeyedService* ExtensionManagementFactory::BuildServiceInstanceFor(
632 content::BrowserContext* context) const {
rkaplowdd66a1342015-03-05 00:31:49633 TRACE_EVENT0("browser,startup",
634 "ExtensionManagementFactory::BuildServiceInstanceFor");
Sergey Poromov741e70702018-10-11 20:11:54635 return new ExtensionManagement(Profile::FromBrowserContext(context));
binjin1569c9b2014-09-05 13:33:18636}
637
binjin9733df12014-09-08 15:21:21638content::BrowserContext* ExtensionManagementFactory::GetBrowserContextToUse(
639 content::BrowserContext* context) const {
640 return chrome::GetBrowserContextRedirectedInIncognito(context);
641}
642
binjinb2454382014-09-22 15:17:43643void ExtensionManagementFactory::RegisterProfilePrefs(
644 user_prefs::PrefRegistrySyncable* user_prefs) {
raymesaa608722015-04-27 03:00:25645 user_prefs->RegisterDictionaryPref(pref_names::kExtensionManagement);
binjinb2454382014-09-22 15:17:43646}
647
binjin5f405ef2014-09-03 21:23:16648} // namespace extensions