[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 5 | #include "chrome/browser/supervised_user/supervised_user_service.h" |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 6 | |
Caio | 6d256c33 | 2019-03-22 15:25:56 | [diff] [blame] | 7 | #include <set> |
dcheng | e73d8520c | 2015-12-27 01:19:09 | [diff] [blame] | 8 | #include <utility> |
| 9 | |
Sebastien Marchand | f1349f5 | 2019-01-25 03:16:41 | [diff] [blame] | 10 | #include "base/bind.h" |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 11 | #include "base/feature_list.h" |
treib | daece84f | 2014-09-05 12:58:15 | [diff] [blame] | 12 | #include "base/files/file_path.h" |
treib | 2fd18739 | 2015-04-16 17:19:38 | [diff] [blame] | 13 | #include "base/files/file_util.h" |
Marc Treib | 9d91df55 | 2018-09-27 14:55:55 | [diff] [blame] | 14 | #include "base/memory/scoped_refptr.h" |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 15 | #include "base/metrics/user_metrics.h" |
treib | d3f8b7a | 2015-04-10 11:41:33 | [diff] [blame] | 16 | #include "base/path_service.h" |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 17 | #include "base/strings/stringprintf.h" |
[email protected] | 112158af | 2013-06-07 23:46:18 | [diff] [blame] | 18 | #include "base/strings/utf_string_conversions.h" |
Gabriel Charette | 44db142 | 2018-08-06 11:19:33 | [diff] [blame] | 19 | #include "base/task/post_task.h" |
treib | f832a99 | 2015-03-24 18:09:24 | [diff] [blame] | 20 | #include "base/version.h" |
avi | 664c07b | 2015-12-26 02:18:31 | [diff] [blame] | 21 | #include "build/build_config.h" |
[email protected] | 5ddfade | 2014-02-03 10:24:53 | [diff] [blame] | 22 | #include "chrome/browser/browser_process.h" |
bauerb | 4da3613 | 2014-12-26 19:53:13 | [diff] [blame] | 23 | #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 24 | #include "chrome/browser/profiles/profile.h" |
Mario Sanchez Prada | 77f113c | 2019-02-01 09:33:55 | [diff] [blame] | 25 | #include "chrome/browser/signin/identity_manager_factory.h" |
treib | e2082a0e | 2015-04-08 10:15:30 | [diff] [blame] | 26 | #include "chrome/browser/supervised_user/experimental/supervised_user_filtering_switches.h" |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 27 | #include "chrome/browser/supervised_user/permission_request_creator.h" |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 28 | #include "chrome/browser/supervised_user/supervised_user_constants.h" |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 29 | #include "chrome/browser/supervised_user/supervised_user_features.h" |
| 30 | #include "chrome/browser/supervised_user/supervised_user_service_factory.h" |
treib | ab0a39e | 2014-09-24 14:48:28 | [diff] [blame] | 31 | #include "chrome/browser/supervised_user/supervised_user_service_observer.h" |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 32 | #include "chrome/browser/supervised_user/supervised_user_settings_service.h" |
| 33 | #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 34 | #include "chrome/browser/supervised_user/supervised_user_site_list.h" |
bauerb | 4da3613 | 2014-12-26 19:53:13 | [diff] [blame] | 35 | #include "chrome/browser/supervised_user/supervised_user_whitelist_service.h" |
[email protected] | 509ad1a9 | 2013-03-19 21:41:06 | [diff] [blame] | 36 | #include "chrome/browser/ui/browser.h" |
[email protected] | dfddd02 | 2013-07-10 17:29:48 | [diff] [blame] | 37 | #include "chrome/browser/ui/browser_list.h" |
treib | d3f8b7a | 2015-04-10 11:41:33 | [diff] [blame] | 38 | #include "chrome/common/chrome_paths.h" |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 39 | #include "chrome/common/pref_names.h" |
[email protected] | af39f00 | 2014-08-22 10:18:18 | [diff] [blame] | 40 | #include "chrome/grit/generated_resources.h" |
Michael Giuffrida | 0fe58bf | 2018-07-26 20:40:27 | [diff] [blame] | 41 | #include "components/policy/core/browser/url_util.h" |
[email protected] | f0c8c499 | 2014-05-15 17:37:26 | [diff] [blame] | 42 | #include "components/pref_registry/pref_registry_syncable.h" |
brettw | b1fc1b8 | 2016-02-02 00:19:08 | [diff] [blame] | 43 | #include "components/prefs/pref_service.h" |
Mark Pilgrim | a8b7f43 | 2018-04-19 23:23:00 | [diff] [blame] | 44 | #include "content/public/browser/browser_context.h" |
Mark Pilgrim | a8b7f43 | 2018-04-19 23:23:00 | [diff] [blame] | 45 | #include "content/public/browser/storage_partition.h" |
Scott Violet | c8240b0 | 2018-03-08 22:03:59 | [diff] [blame] | 46 | #include "extensions/buildflags/buildflags.h" |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 47 | #include "net/traffic_annotation/network_traffic_annotation.h" |
Mario Sanchez Prada | 77f113c | 2019-02-01 09:33:55 | [diff] [blame] | 48 | #include "services/identity/public/cpp/accounts_mutator.h" |
| 49 | #include "services/identity/public/cpp/identity_manager.h" |
Mark Pilgrim | b67362ed | 2018-05-15 15:59:47 | [diff] [blame] | 50 | #include "services/network/public/cpp/shared_url_loader_factory.h" |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 51 | #include "ui/base/l10n/l10n_util.h" |
| 52 | |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 53 | #if !defined(OS_ANDROID) |
brettw | 9b0866f | 2016-12-11 02:34:06 | [diff] [blame] | 54 | #include "chrome/browser/themes/theme_service.h" |
| 55 | #include "chrome/browser/themes/theme_service_factory.h" |
thestig | 1b76f1a | 2015-09-30 22:52:38 | [diff] [blame] | 56 | #endif |
| 57 | |
[email protected] | 3aacc9c | 2013-08-08 11:19:31 | [diff] [blame] | 58 | #if defined(OS_CHROMEOS) |
[email protected] | 4d39078 | 2014-08-15 09:22:58 | [diff] [blame] | 59 | #include "chrome/browser/chromeos/login/users/chrome_user_manager.h" |
[email protected] | 83d82d4 | 2014-05-16 02:04:42 | [diff] [blame] | 60 | #include "chrome/browser/chromeos/login/users/supervised_user_manager.h" |
[email protected] | 4d39078 | 2014-08-15 09:22:58 | [diff] [blame] | 61 | #include "components/user_manager/user_manager.h" |
[email protected] | 3aacc9c | 2013-08-08 11:19:31 | [diff] [blame] | 62 | #endif |
| 63 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 64 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
treib | 9e30e30 | 2015-04-15 08:12:16 | [diff] [blame] | 65 | #include "chrome/browser/extensions/extension_service.h" |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 66 | #include "chrome/browser/extensions/extension_util.h" |
| 67 | #include "extensions/browser/extension_prefs.h" |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 68 | #include "extensions/browser/extension_registry.h" |
[email protected] | c14a680 | 2014-07-11 21:51:12 | [diff] [blame] | 69 | #include "extensions/browser/extension_system.h" |
[email protected] | c14a680 | 2014-07-11 21:51:12 | [diff] [blame] | 70 | #endif |
| 71 | |
[email protected] | 2056c3b | 2014-04-07 18:08:50 | [diff] [blame] | 72 | using base::UserMetricsAction; |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 73 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 74 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 75 | using extensions::Extension; |
| 76 | using extensions::ExtensionPrefs; |
| 77 | using extensions::ExtensionRegistry; |
| 78 | using extensions::ExtensionSystem; |
| 79 | #endif |
| 80 | |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 81 | namespace { |
| 82 | |
treib | d3f8b7a | 2015-04-10 11:41:33 | [diff] [blame] | 83 | // The URL from which to download a host blacklist if no local one exists yet. |
| 84 | const char kBlacklistURL[] = |
| 85 | "https://www.gstatic.com/chrome/supervised_user/blacklist-20141001-1k.bin"; |
| 86 | // The filename under which we'll store the blacklist (in the user data dir). |
| 87 | const char kBlacklistFilename[] = "su-blacklist.bin"; |
| 88 | |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 89 | const char* const kCustodianInfoPrefs[] = { |
| 90 | prefs::kSupervisedUserCustodianName, |
| 91 | prefs::kSupervisedUserCustodianEmail, |
| 92 | prefs::kSupervisedUserCustodianProfileImageURL, |
| 93 | prefs::kSupervisedUserCustodianProfileURL, |
| 94 | prefs::kSupervisedUserSecondCustodianName, |
| 95 | prefs::kSupervisedUserSecondCustodianEmail, |
| 96 | prefs::kSupervisedUserSecondCustodianProfileImageURL, |
| 97 | prefs::kSupervisedUserSecondCustodianProfileURL, |
| 98 | }; |
| 99 | |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 100 | void CreateURLAccessRequest(const GURL& url, |
| 101 | PermissionRequestCreator* creator, |
| 102 | SupervisedUserService::SuccessCallback callback) { |
| 103 | creator->CreateURLAccessRequest(url, std::move(callback)); |
treib | 8ecc1eb5 | 2015-03-04 18:29:06 | [diff] [blame] | 104 | } |
| 105 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 106 | void CreateExtensionInstallRequest( |
| 107 | const std::string& id, |
| 108 | PermissionRequestCreator* creator, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 109 | SupervisedUserService::SuccessCallback callback) { |
| 110 | creator->CreateExtensionInstallRequest(id, std::move(callback)); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 111 | } |
| 112 | |
treib | 8ecc1eb5 | 2015-03-04 18:29:06 | [diff] [blame] | 113 | void CreateExtensionUpdateRequest( |
treib | f832a99 | 2015-03-24 18:09:24 | [diff] [blame] | 114 | const std::string& id, |
treib | 8ecc1eb5 | 2015-03-04 18:29:06 | [diff] [blame] | 115 | PermissionRequestCreator* creator, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 116 | SupervisedUserService::SuccessCallback callback) { |
| 117 | creator->CreateExtensionUpdateRequest(id, std::move(callback)); |
treib | 8ecc1eb5 | 2015-03-04 18:29:06 | [diff] [blame] | 118 | } |
| 119 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 120 | // Default callback for AddExtensionInstallRequest. |
| 121 | void ExtensionInstallRequestSent(const std::string& id, bool success) { |
| 122 | VLOG_IF(1, !success) << "Failed sending install request for " << id; |
| 123 | } |
| 124 | |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 125 | // Default callback for AddExtensionUpdateRequest. |
| 126 | void ExtensionUpdateRequestSent(const std::string& id, bool success) { |
| 127 | VLOG_IF(1, !success) << "Failed sending update request for " << id; |
| 128 | } |
| 129 | |
treib | d3f8b7a | 2015-04-10 11:41:33 | [diff] [blame] | 130 | base::FilePath GetBlacklistPath() { |
| 131 | base::FilePath blacklist_dir; |
Avi Drissman | 9098f900 | 2018-05-04 00:11:52 | [diff] [blame] | 132 | base::PathService::Get(chrome::DIR_USER_DATA, &blacklist_dir); |
treib | d3f8b7a | 2015-04-10 11:41:33 | [diff] [blame] | 133 | return blacklist_dir.AppendASCII(kBlacklistFilename); |
| 134 | } |
| 135 | |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 136 | } // namespace |
| 137 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 138 | SupervisedUserService::~SupervisedUserService() { |
| 139 | DCHECK(!did_init_ || did_shutdown_); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 140 | url_filter_.RemoveObserver(this); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | // static |
| 144 | void SupervisedUserService::RegisterProfilePrefs( |
| 145 | user_prefs::PrefRegistrySyncable* registry) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 146 | registry->RegisterDictionaryPref(prefs::kSupervisedUserApprovedExtensions); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 147 | registry->RegisterDictionaryPref(prefs::kSupervisedUserManualHosts); |
| 148 | registry->RegisterDictionaryPref(prefs::kSupervisedUserManualURLs); |
| 149 | registry->RegisterIntegerPref(prefs::kDefaultSupervisedUserFilteringBehavior, |
| 150 | SupervisedUserURLFilter::ALLOW); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 151 | registry->RegisterBooleanPref(prefs::kSupervisedUserSafeSites, true); |
| 152 | for (const char* pref : kCustodianInfoPrefs) { |
| 153 | registry->RegisterStringPref(pref, std::string()); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | void SupervisedUserService::Init() { |
| 158 | DCHECK(!did_init_); |
| 159 | did_init_ = true; |
| 160 | DCHECK(GetSettingsService()->IsReady()); |
| 161 | |
| 162 | pref_change_registrar_.Init(profile_->GetPrefs()); |
| 163 | pref_change_registrar_.Add( |
| 164 | prefs::kSupervisedUserId, |
| 165 | base::Bind(&SupervisedUserService::OnSupervisedUserIdChanged, |
| 166 | base::Unretained(this))); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 167 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 168 | whitelist_service_->AddSiteListsChangedCallback( |
| 169 | base::Bind(&SupervisedUserService::OnSiteListsChanged, |
| 170 | weak_ptr_factory_.GetWeakPtr())); |
| 171 | |
| 172 | SetActive(ProfileIsSupervised()); |
| 173 | } |
| 174 | |
| 175 | void SupervisedUserService::SetDelegate(Delegate* delegate) { |
| 176 | if (delegate) { |
| 177 | // Changing delegates isn't allowed. |
| 178 | DCHECK(!delegate_); |
| 179 | } else { |
| 180 | // If the delegate is removed, deactivate first to give the old delegate a |
| 181 | // chance to clean up. |
| 182 | SetActive(false); |
| 183 | } |
| 184 | delegate_ = delegate; |
| 185 | } |
| 186 | |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 187 | SupervisedUserURLFilter* SupervisedUserService::GetURLFilter() { |
| 188 | return &url_filter_; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | SupervisedUserWhitelistService* SupervisedUserService::GetWhitelistService() { |
| 192 | return whitelist_service_.get(); |
| 193 | } |
| 194 | |
| 195 | bool SupervisedUserService::AccessRequestsEnabled() { |
| 196 | return FindEnabledPermissionRequestCreator(0) < permissions_creators_.size(); |
| 197 | } |
| 198 | |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 199 | void SupervisedUserService::AddURLAccessRequest(const GURL& url, |
| 200 | SuccessCallback callback) { |
Michael Giuffrida | 0fe58bf | 2018-07-26 20:40:27 | [diff] [blame] | 201 | GURL effective_url = policy::url_util::GetEmbeddedURL(url); |
treib | 17f2e38 | 2016-10-14 11:42:53 | [diff] [blame] | 202 | if (!effective_url.is_valid()) |
| 203 | effective_url = url; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 204 | AddPermissionRequestInternal( |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 205 | base::BindRepeating(CreateURLAccessRequest, |
Michael Giuffrida | 0fe58bf | 2018-07-26 20:40:27 | [diff] [blame] | 206 | policy::url_util::Normalize(effective_url)), |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 207 | std::move(callback), 0); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 208 | } |
| 209 | |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 210 | void SupervisedUserService::ReportURL(const GURL& url, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 211 | SuccessCallback callback) { |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 212 | if (url_reporter_) |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 213 | url_reporter_->ReportUrl(url, std::move(callback)); |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 214 | else |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 215 | std::move(callback).Run(false); |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 216 | } |
| 217 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 218 | void SupervisedUserService::AddExtensionInstallRequest( |
| 219 | const std::string& extension_id, |
| 220 | const base::Version& version, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 221 | SuccessCallback callback) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 222 | std::string id = GetExtensionRequestId(extension_id, version); |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 223 | AddPermissionRequestInternal( |
| 224 | base::BindRepeating(CreateExtensionInstallRequest, id), |
| 225 | std::move(callback), 0); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | void SupervisedUserService::AddExtensionInstallRequest( |
| 229 | const std::string& extension_id, |
| 230 | const base::Version& version) { |
| 231 | std::string id = GetExtensionRequestId(extension_id, version); |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 232 | AddExtensionInstallRequest(extension_id, version, |
| 233 | base::BindOnce(ExtensionInstallRequestSent, id)); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 234 | } |
| 235 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 236 | void SupervisedUserService::AddExtensionUpdateRequest( |
| 237 | const std::string& extension_id, |
| 238 | const base::Version& version, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 239 | SuccessCallback callback) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 240 | std::string id = GetExtensionRequestId(extension_id, version); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 241 | AddPermissionRequestInternal( |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 242 | base::BindRepeating(CreateExtensionUpdateRequest, id), |
| 243 | std::move(callback), 0); |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | void SupervisedUserService::AddExtensionUpdateRequest( |
| 247 | const std::string& extension_id, |
| 248 | const base::Version& version) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 249 | std::string id = GetExtensionRequestId(extension_id, version); |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 250 | AddExtensionUpdateRequest(extension_id, version, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 251 | base::BindOnce(ExtensionUpdateRequestSent, id)); |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 252 | } |
| 253 | |
| 254 | // static |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 255 | std::string SupervisedUserService::GetExtensionRequestId( |
treib | 40d3ad9 | 2015-10-20 18:15:42 | [diff] [blame] | 256 | const std::string& extension_id, |
| 257 | const base::Version& version) { |
| 258 | return base::StringPrintf("%s:%s", extension_id.c_str(), |
| 259 | version.GetString().c_str()); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | std::string SupervisedUserService::GetCustodianEmailAddress() const { |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 263 | std::string email = profile_->GetPrefs()->GetString( |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 264 | prefs::kSupervisedUserCustodianEmail); |
| 265 | #if defined(OS_CHROMEOS) |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 266 | // |GetActiveUser()| can return null in unit tests. |
| 267 | if (email.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) { |
| 268 | email = chromeos::ChromeUserManager::Get() |
alemate | 1e3ddde | 2016-11-04 02:17:06 | [diff] [blame] | 269 | ->GetSupervisedUserManager() |
| 270 | ->GetManagerDisplayEmail(user_manager::UserManager::Get() |
| 271 | ->GetActiveUser() |
| 272 | ->GetAccountId() |
| 273 | .GetUserEmail()); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 274 | } |
| 275 | #endif |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 276 | return email; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 277 | } |
| 278 | |
| 279 | std::string SupervisedUserService::GetCustodianName() const { |
| 280 | std::string name = profile_->GetPrefs()->GetString( |
| 281 | prefs::kSupervisedUserCustodianName); |
| 282 | #if defined(OS_CHROMEOS) |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 283 | // |GetActiveUser()| can return null in unit tests. |
| 284 | if (name.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) { |
alemate | 1e3ddde | 2016-11-04 02:17:06 | [diff] [blame] | 285 | name = base::UTF16ToUTF8( |
| 286 | chromeos::ChromeUserManager::Get() |
| 287 | ->GetSupervisedUserManager() |
| 288 | ->GetManagerDisplayName(user_manager::UserManager::Get() |
| 289 | ->GetActiveUser() |
| 290 | ->GetAccountId() |
| 291 | .GetUserEmail())); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 292 | } |
| 293 | #endif |
| 294 | return name.empty() ? GetCustodianEmailAddress() : name; |
| 295 | } |
| 296 | |
| 297 | std::string SupervisedUserService::GetSecondCustodianEmailAddress() const { |
| 298 | return profile_->GetPrefs()->GetString( |
| 299 | prefs::kSupervisedUserSecondCustodianEmail); |
| 300 | } |
| 301 | |
| 302 | std::string SupervisedUserService::GetSecondCustodianName() const { |
| 303 | std::string name = profile_->GetPrefs()->GetString( |
| 304 | prefs::kSupervisedUserSecondCustodianName); |
| 305 | return name.empty() ? GetSecondCustodianEmailAddress() : name; |
| 306 | } |
| 307 | |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 308 | base::string16 SupervisedUserService::GetExtensionsLockedMessage() const { |
| 309 | return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER, |
| 310 | base::UTF8ToUTF16(GetCustodianName())); |
| 311 | } |
| 312 | |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 313 | #if !defined(OS_ANDROID) |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 314 | void SupervisedUserService::InitSync(const std::string& refresh_token) { |
Mario Sanchez Prada | 77f113c | 2019-02-01 09:33:55 | [diff] [blame] | 315 | IdentityManagerFactory::GetForProfile(profile_) |
| 316 | ->GetAccountsMutator() |
| 317 | ->LegacySetRefreshTokenForSupervisedUser(refresh_token); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 318 | } |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 319 | #endif // !defined(OS_ANDROID) |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 320 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 321 | void SupervisedUserService::AddObserver( |
| 322 | SupervisedUserServiceObserver* observer) { |
| 323 | observer_list_.AddObserver(observer); |
| 324 | } |
| 325 | |
| 326 | void SupervisedUserService::RemoveObserver( |
| 327 | SupervisedUserServiceObserver* observer) { |
| 328 | observer_list_.RemoveObserver(observer); |
| 329 | } |
| 330 | |
| 331 | void SupervisedUserService::AddPermissionRequestCreator( |
dcheng | f624e47 | 2016-04-12 08:33:17 | [diff] [blame] | 332 | std::unique_ptr<PermissionRequestCreator> creator) { |
leon.han | 4ea301f | 2017-03-28 03:36:31 | [diff] [blame] | 333 | permissions_creators_.push_back(std::move(creator)); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 334 | } |
| 335 | |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 336 | void SupervisedUserService::SetSafeSearchURLReporter( |
dcheng | f624e47 | 2016-04-12 08:33:17 | [diff] [blame] | 337 | std::unique_ptr<SafeSearchURLReporter> reporter) { |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 338 | url_reporter_ = std::move(reporter); |
| 339 | } |
| 340 | |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 341 | SupervisedUserService::SupervisedUserService(Profile* profile) |
Marc Treib | 81f6d60 | 2018-11-07 10:10:34 | [diff] [blame] | 342 | : profile_(profile), |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 343 | active_(false), |
| 344 | delegate_(NULL), |
[email protected] | dfddd02 | 2013-07-10 17:29:48 | [diff] [blame] | 345 | is_profile_active_(false), |
[email protected] | 3a276ff | 2014-08-12 14:22:09 | [diff] [blame] | 346 | did_init_(false), |
[email protected] | 8052b24 | 2013-11-15 16:40:55 | [diff] [blame] | 347 | did_shutdown_(false), |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 348 | blacklist_state_(BlacklistLoadState::NOT_LOADED), |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 349 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 350 | registry_observer_(this), |
| 351 | #endif |
[email protected] | 8052b24 | 2013-11-15 16:40:55 | [diff] [blame] | 352 | weak_ptr_factory_(this) { |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 353 | url_filter_.AddObserver(this); |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 354 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 355 | registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); |
| 356 | #endif |
Marc Treib | 974d8f8 | 2019-03-28 12:21:36 | [diff] [blame] | 357 | |
| 358 | std::string client_id = component_updater::SupervisedUserWhitelistInstaller:: |
| 359 | ClientIdForProfilePath(profile_->GetPath()); |
| 360 | whitelist_service_ = std::make_unique<SupervisedUserWhitelistService>( |
| 361 | profile_->GetPrefs(), |
| 362 | g_browser_process->supervised_user_whitelist_installer(), client_id); |
[email protected] | a243d644c | 2013-06-20 18:37:55 | [diff] [blame] | 363 | } |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 364 | |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 365 | void SupervisedUserService::SetActive(bool active) { |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 366 | if (active_ == active) |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 367 | return; |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 368 | active_ = active; |
| 369 | |
| 370 | if (!delegate_ || !delegate_->SetActive(active_)) { |
| 371 | if (active_) { |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 372 | #if !defined(OS_ANDROID) |
Henrique Ferreiro | e27d42d | 2019-02-20 01:32:20 | [diff] [blame] | 373 | IdentityManagerFactory::GetForProfile(profile_) |
Sylvain Defresne | 8ee06f2 | 2019-03-08 15:01:16 | [diff] [blame] | 374 | ->DeprecatedLoadCredentialsForSupervisedUser( |
Henrique Ferreiro | e27d42d | 2019-02-20 01:32:20 | [diff] [blame] | 375 | supervised_users::kSupervisedUserPseudoEmail); |
bauerb | 7f3b854 | 2015-06-29 19:56:19 | [diff] [blame] | 376 | #else |
| 377 | NOTREACHED(); |
| 378 | #endif |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 379 | } |
[email protected] | e861bba | 2013-06-17 15:20:54 | [diff] [blame] | 380 | } |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 381 | |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 382 | // Now activate/deactivate anything not handled by the delegate yet. |
[email protected] | e148048 | 2013-09-11 11:49:58 | [diff] [blame] | 383 | |
brettw | 9b0866f | 2016-12-11 02:34:06 | [diff] [blame] | 384 | #if !defined(OS_ANDROID) |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 385 | // Re-set the default theme to turn the SU theme on/off. |
| 386 | ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_); |
treib | 9e30e30 | 2015-04-15 08:12:16 | [diff] [blame] | 387 | if (theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme()) |
| 388 | theme_service->UseDefaultTheme(); |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 389 | #endif |
[email protected] | a19df3e | 2013-05-21 00:03:03 | [diff] [blame] | 390 | |
bauerb | d3a36cc4 | 2014-10-01 13:05:49 | [diff] [blame] | 391 | GetSettingsService()->SetActive(active_); |
[email protected] | a243d644c | 2013-06-20 18:37:55 | [diff] [blame] | 392 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 393 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
[email protected] | c14a680 | 2014-07-11 21:51:12 | [diff] [blame] | 394 | SetExtensionsActive(); |
| 395 | #endif |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 396 | |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 397 | if (active_) { |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 398 | pref_change_registrar_.Add( |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 399 | prefs::kDefaultSupervisedUserFilteringBehavior, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 400 | base::BindRepeating( |
| 401 | &SupervisedUserService::OnDefaultFilteringBehaviorChanged, |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 402 | base::Unretained(this))); |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 403 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 404 | pref_change_registrar_.Add( |
| 405 | prefs::kSupervisedUserApprovedExtensions, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 406 | base::BindRepeating(&SupervisedUserService::UpdateApprovedExtensions, |
| 407 | base::Unretained(this))); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 408 | #endif |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 409 | pref_change_registrar_.Add( |
| 410 | prefs::kSupervisedUserSafeSites, |
| 411 | base::BindRepeating(&SupervisedUserService::OnSafeSitesSettingChanged, |
| 412 | base::Unretained(this))); |
| 413 | pref_change_registrar_.Add( |
| 414 | prefs::kSupervisedUserManualHosts, |
| 415 | base::BindRepeating(&SupervisedUserService::UpdateManualHosts, |
| 416 | base::Unretained(this))); |
| 417 | pref_change_registrar_.Add( |
| 418 | prefs::kSupervisedUserManualURLs, |
| 419 | base::BindRepeating(&SupervisedUserService::UpdateManualURLs, |
| 420 | base::Unretained(this))); |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 421 | for (const char* pref : kCustodianInfoPrefs) { |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 422 | pref_change_registrar_.Add( |
| 423 | pref, |
| 424 | base::BindRepeating(&SupervisedUserService::OnCustodianInfoChanged, |
| 425 | base::Unretained(this))); |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 426 | } |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 427 | |
| 428 | // Initialize the filter. |
| 429 | OnDefaultFilteringBehaviorChanged(); |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 430 | OnSafeSitesSettingChanged(); |
bauerb | 4da3613 | 2014-12-26 19:53:13 | [diff] [blame] | 431 | whitelist_service_->Init(); |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 432 | UpdateManualHosts(); |
| 433 | UpdateManualURLs(); |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 434 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 435 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 436 | UpdateApprovedExtensions(); |
| 437 | #endif |
| 438 | |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 439 | #if !defined(OS_ANDROID) |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 440 | // TODO(bauerb): Get rid of the platform-specific #ifdef here. |
| 441 | // http://crbug.com/313377 |
| 442 | BrowserList::AddObserver(this); |
[email protected] | 975677d | 2013-11-14 16:15:34 | [diff] [blame] | 443 | #endif |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 444 | } else { |
bauerb | d3a36cc4 | 2014-10-01 13:05:49 | [diff] [blame] | 445 | permissions_creators_.clear(); |
atanasova | ac67603 | 2016-04-05 16:31:05 | [diff] [blame] | 446 | url_reporter_.reset(); |
[email protected] | dfddd02 | 2013-07-10 17:29:48 | [diff] [blame] | 447 | |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 448 | pref_change_registrar_.Remove( |
| 449 | prefs::kDefaultSupervisedUserFilteringBehavior); |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 450 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 451 | pref_change_registrar_.Remove(prefs::kSupervisedUserApprovedExtensions); |
| 452 | #endif |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 453 | pref_change_registrar_.Remove(prefs::kSupervisedUserManualHosts); |
| 454 | pref_change_registrar_.Remove(prefs::kSupervisedUserManualURLs); |
treib | 22c3a04 | 2015-01-15 21:30:13 | [diff] [blame] | 455 | for (const char* pref : kCustodianInfoPrefs) { |
| 456 | pref_change_registrar_.Remove(pref); |
| 457 | } |
| 458 | |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 459 | url_filter_.Clear(); |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 460 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 461 | observer.OnURLFilterChanged(); |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 462 | |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 463 | #if !defined(OS_ANDROID) |
[email protected] | f085fdd5 | 2014-06-11 18:09:20 | [diff] [blame] | 464 | // TODO(bauerb): Get rid of the platform-specific #ifdef here. |
| 465 | // http://crbug.com/313377 |
| 466 | BrowserList::RemoveObserver(this); |
| 467 | #endif |
| 468 | } |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 469 | } |
| 470 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 471 | bool SupervisedUserService::ProfileIsSupervised() const { |
| 472 | return profile_->IsSupervised(); |
| 473 | } |
| 474 | |
| 475 | void SupervisedUserService::OnCustodianInfoChanged() { |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 476 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 477 | observer.OnCustodianInfoChanged(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 478 | } |
| 479 | |
| 480 | SupervisedUserSettingsService* SupervisedUserService::GetSettingsService() { |
| 481 | return SupervisedUserSettingsServiceFactory::GetForProfile(profile_); |
| 482 | } |
| 483 | |
| 484 | size_t SupervisedUserService::FindEnabledPermissionRequestCreator( |
| 485 | size_t start) { |
| 486 | for (size_t i = start; i < permissions_creators_.size(); ++i) { |
| 487 | if (permissions_creators_[i]->IsEnabled()) |
| 488 | return i; |
| 489 | } |
| 490 | return permissions_creators_.size(); |
| 491 | } |
| 492 | |
| 493 | void SupervisedUserService::AddPermissionRequestInternal( |
| 494 | const CreatePermissionRequestCallback& create_request, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 495 | SuccessCallback callback, |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 496 | size_t index) { |
| 497 | // Find a permission request creator that is enabled. |
| 498 | size_t next_index = FindEnabledPermissionRequestCreator(index); |
| 499 | if (next_index >= permissions_creators_.size()) { |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 500 | std::move(callback).Run(false); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 501 | return; |
| 502 | } |
| 503 | |
| 504 | create_request.Run( |
leon.han | 4ea301f | 2017-03-28 03:36:31 | [diff] [blame] | 505 | permissions_creators_[next_index].get(), |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 506 | base::BindOnce(&SupervisedUserService::OnPermissionRequestIssued, |
| 507 | weak_ptr_factory_.GetWeakPtr(), create_request, |
| 508 | std::move(callback), next_index)); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | void SupervisedUserService::OnPermissionRequestIssued( |
| 512 | const CreatePermissionRequestCallback& create_request, |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 513 | SuccessCallback callback, |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 514 | size_t index, |
| 515 | bool success) { |
| 516 | if (success) { |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 517 | std::move(callback).Run(true); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 518 | return; |
| 519 | } |
| 520 | |
Carlos IL | 6b784a6 | 2018-03-20 00:26:49 | [diff] [blame] | 521 | AddPermissionRequestInternal(create_request, std::move(callback), index + 1); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 522 | } |
| 523 | |
| 524 | void SupervisedUserService::OnSupervisedUserIdChanged() { |
| 525 | SetActive(ProfileIsSupervised()); |
| 526 | } |
| 527 | |
| 528 | void SupervisedUserService::OnDefaultFilteringBehaviorChanged() { |
| 529 | int behavior_value = profile_->GetPrefs()->GetInteger( |
| 530 | prefs::kDefaultSupervisedUserFilteringBehavior); |
| 531 | SupervisedUserURLFilter::FilteringBehavior behavior = |
| 532 | SupervisedUserURLFilter::BehaviorFromInt(behavior_value); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 533 | url_filter_.SetDefaultFilteringBehavior(behavior); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 534 | |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 535 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 536 | observer.OnURLFilterChanged(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 537 | } |
| 538 | |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 539 | void SupervisedUserService::OnSafeSitesSettingChanged() { |
| 540 | bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 541 | if (use_blacklist != url_filter_.HasBlacklist()) { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 542 | if (use_blacklist && blacklist_state_ == BlacklistLoadState::NOT_LOADED) { |
| 543 | LoadBlacklist(GetBlacklistPath(), GURL(kBlacklistURL)); |
| 544 | } else if (!use_blacklist || |
| 545 | blacklist_state_ == BlacklistLoadState::LOADED) { |
| 546 | // Either the blacklist was turned off, or it was turned on but has |
| 547 | // already been loaded previously. Just update the setting. |
| 548 | UpdateBlacklist(); |
| 549 | } |
| 550 | // Else: The blacklist was enabled, but the load is already in progress. |
| 551 | // Do nothing - we'll check the setting again when the load finishes. |
| 552 | } |
| 553 | |
| 554 | bool use_online_check = |
| 555 | supervised_users::IsSafeSitesOnlineCheckEnabled(profile_); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 556 | if (use_online_check != url_filter_.HasAsyncURLChecker()) { |
Caio | 6d256c33 | 2019-03-22 15:25:56 | [diff] [blame] | 557 | if (use_online_check) { |
Mark Pilgrim | b67362ed | 2018-05-15 15:59:47 | [diff] [blame] | 558 | url_filter_.InitAsyncURLChecker( |
| 559 | content::BrowserContext::GetDefaultStoragePartition(profile_) |
Caio | 6d256c33 | 2019-03-22 15:25:56 | [diff] [blame] | 560 | ->GetURLLoaderFactoryForBrowserProcess(), |
| 561 | IdentityManagerFactory::GetForProfile(profile_)); |
| 562 | } else { |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 563 | url_filter_.ClearAsyncURLChecker(); |
Caio | 6d256c33 | 2019-03-22 15:25:56 | [diff] [blame] | 564 | } |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 565 | } |
| 566 | } |
| 567 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 568 | void SupervisedUserService::OnSiteListsChanged( |
| 569 | const std::vector<scoped_refptr<SupervisedUserSiteList> >& site_lists) { |
atanasova | 9572aaf | 2016-02-26 18:08:26 | [diff] [blame] | 570 | whitelists_ = site_lists; |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 571 | url_filter_.LoadWhitelists(site_lists); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 572 | } |
| 573 | |
| 574 | void SupervisedUserService::LoadBlacklist(const base::FilePath& path, |
| 575 | const GURL& url) { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 576 | DCHECK(blacklist_state_ == BlacklistLoadState::NOT_LOADED); |
| 577 | blacklist_state_ = BlacklistLoadState::LOAD_STARTED; |
fdoray | 9afc2bc | 2017-04-27 15:00:00 | [diff] [blame] | 578 | base::PostTaskWithTraitsAndReplyWithResult( |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 579 | FROM_HERE, |
Gabriel Charette | b10aeebc | 2018-07-26 20:15:00 | [diff] [blame] | 580 | {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
fdoray | 4ad1493 | 2017-05-03 21:21:11 | [diff] [blame] | 581 | base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
fdoray | 9afc2bc | 2017-04-27 15:00:00 | [diff] [blame] | 582 | base::BindOnce(&base::PathExists, path), |
| 583 | base::BindOnce(&SupervisedUserService::OnBlacklistFileChecked, |
| 584 | weak_ptr_factory_.GetWeakPtr(), path, url)); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 585 | } |
| 586 | |
| 587 | void SupervisedUserService::OnBlacklistFileChecked(const base::FilePath& path, |
| 588 | const GURL& url, |
| 589 | bool file_exists) { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 590 | DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 591 | if (file_exists) { |
| 592 | LoadBlacklistFromFile(path); |
| 593 | return; |
| 594 | } |
| 595 | |
| 596 | DCHECK(!blacklist_downloader_); |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 597 | |
| 598 | // Create traffic annotation tag. |
| 599 | net::NetworkTrafficAnnotationTag traffic_annotation = |
| 600 | net::DefineNetworkTrafficAnnotation("supervised_users_blacklist", R"( |
| 601 | semantics { |
| 602 | sender: "Supervised Users" |
| 603 | description: |
| 604 | "Downloads a static blacklist consisting of hostname hashes of " |
| 605 | "common inappropriate websites. This is only enabled for child " |
| 606 | "accounts and only if the corresponding setting is enabled by the " |
| 607 | "parent." |
| 608 | trigger: |
| 609 | "The file is downloaded on demand if the child account profile is " |
| 610 | "created and the setting is enabled." |
| 611 | data: |
| 612 | "No additional data is sent to the server beyond the request " |
| 613 | "itself." |
| 614 | destination: GOOGLE_OWNED_SERVICE |
| 615 | } |
| 616 | policy { |
Ramin Halavati | 3b97978 | 2017-07-21 11:40:26 | [diff] [blame] | 617 | cookies_allowed: NO |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 618 | setting: |
| 619 | "The feature can be remotely enabled or disabled by the parent. In " |
| 620 | "addition, if sign-in is restricted to accounts from a managed " |
| 621 | "domain, those accounts are not going to be child accounts." |
rhalavati | eaa64e9 | 2017-04-03 09:36:43 | [diff] [blame] | 622 | chrome_policy { |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 623 | RestrictSigninToPattern { |
| 624 | policy_options {mode: MANDATORY} |
rhalavati | eaa64e9 | 2017-04-03 09:36:43 | [diff] [blame] | 625 | RestrictSigninToPattern: "*@manageddomain.com" |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 626 | } |
| 627 | } |
| 628 | })"); |
| 629 | |
Mark Pilgrim | a8b7f43 | 2018-04-19 23:23:00 | [diff] [blame] | 630 | auto factory = content::BrowserContext::GetDefaultStoragePartition(profile_) |
| 631 | ->GetURLLoaderFactoryForBrowserProcess(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 632 | blacklist_downloader_.reset(new FileDownloader( |
Mark Pilgrim | a8b7f43 | 2018-04-19 23:23:00 | [diff] [blame] | 633 | url, path, false, std::move(factory), |
Mark Pilgrim | fa634c9 | 2018-06-19 20:01:24 | [diff] [blame] | 634 | base::BindOnce(&SupervisedUserService::OnBlacklistDownloadDone, |
| 635 | base::Unretained(this), path), |
rhalavati | 5f1caa2b | 2017-02-25 08:22:16 | [diff] [blame] | 636 | traffic_annotation)); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 637 | } |
| 638 | |
| 639 | void SupervisedUserService::LoadBlacklistFromFile(const base::FilePath& path) { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 640 | DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED); |
| 641 | blacklist_.ReadFromFile( |
| 642 | path, |
| 643 | base::Bind(&SupervisedUserService::OnBlacklistLoaded, |
| 644 | base::Unretained(this))); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 645 | } |
| 646 | |
treib | f38cc25 | 2016-04-07 14:44:11 | [diff] [blame] | 647 | void SupervisedUserService::OnBlacklistDownloadDone( |
| 648 | const base::FilePath& path, |
| 649 | FileDownloader::Result result) { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 650 | DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED); |
treib | f38cc25 | 2016-04-07 14:44:11 | [diff] [blame] | 651 | if (FileDownloader::IsSuccess(result)) { |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 652 | LoadBlacklistFromFile(path); |
| 653 | } else { |
| 654 | LOG(WARNING) << "Blacklist download failed"; |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 655 | // TODO(treib): Retry downloading after some time? |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 656 | } |
| 657 | blacklist_downloader_.reset(); |
| 658 | } |
| 659 | |
| 660 | void SupervisedUserService::OnBlacklistLoaded() { |
treib | 9cc1b11 | 2016-01-08 10:08:01 | [diff] [blame] | 661 | DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED); |
| 662 | blacklist_state_ = BlacklistLoadState::LOADED; |
| 663 | UpdateBlacklist(); |
| 664 | } |
| 665 | |
| 666 | void SupervisedUserService::UpdateBlacklist() { |
| 667 | bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 668 | url_filter_.SetBlacklist(use_blacklist ? &blacklist_ : nullptr); |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 669 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 670 | observer.OnURLFilterChanged(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 671 | } |
[email protected] | acfcfbb | 2013-05-13 18:01:27 | [diff] [blame] | 672 | |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 673 | void SupervisedUserService::UpdateManualHosts() { |
[email protected] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 674 | const base::DictionaryValue* dict = |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 675 | profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualHosts); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 676 | std::map<std::string, bool> host_map; |
[email protected] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 677 | for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { |
[email protected] | 5e02229 | 2013-02-06 16:42:17 | [diff] [blame] | 678 | bool allow = false; |
| 679 | bool result = it.value().GetAsBoolean(&allow); |
| 680 | DCHECK(result); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 681 | host_map[it.key()] = allow; |
[email protected] | 5e02229 | 2013-02-06 16:42:17 | [diff] [blame] | 682 | } |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 683 | url_filter_.SetManualHosts(std::move(host_map)); |
treib | ab0a39e | 2014-09-24 14:48:28 | [diff] [blame] | 684 | |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 685 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 686 | observer.OnURLFilterChanged(); |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 687 | } |
| 688 | |
[email protected] | cce15bb | 2014-06-17 13:43:51 | [diff] [blame] | 689 | void SupervisedUserService::UpdateManualURLs() { |
[email protected] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 690 | const base::DictionaryValue* dict = |
[email protected] | d20d043 | 2014-06-12 17:14:05 | [diff] [blame] | 691 | profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 692 | std::map<GURL, bool> url_map; |
[email protected] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 693 | for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { |
[email protected] | 5e02229 | 2013-02-06 16:42:17 | [diff] [blame] | 694 | bool allow = false; |
| 695 | bool result = it.value().GetAsBoolean(&allow); |
| 696 | DCHECK(result); |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 697 | url_map[GURL(it.key())] = allow; |
[email protected] | 5e02229 | 2013-02-06 16:42:17 | [diff] [blame] | 698 | } |
mmenke | db2637ff | 2017-03-30 23:59:42 | [diff] [blame] | 699 | url_filter_.SetManualURLs(std::move(url_map)); |
treib | ab0a39e | 2014-09-24 14:48:28 | [diff] [blame] | 700 | |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 701 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 702 | observer.OnURLFilterChanged(); |
[email protected] | 0850e84 | 2013-01-19 03:44:31 | [diff] [blame] | 703 | } |
[email protected] | dfddd02 | 2013-07-10 17:29:48 | [diff] [blame] | 704 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 705 | void SupervisedUserService::Shutdown() { |
| 706 | if (!did_init_) |
| 707 | return; |
| 708 | DCHECK(!did_shutdown_); |
| 709 | did_shutdown_ = true; |
| 710 | if (ProfileIsSupervised()) { |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 711 | base::RecordAction(UserMetricsAction("ManagedUsers_QuitBrowser")); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 712 | } |
| 713 | SetActive(false); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 714 | } |
| 715 | |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 716 | #if BUILDFLAG(ENABLE_EXTENSIONS) |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 717 | SupervisedUserService::ExtensionState SupervisedUserService::GetExtensionState( |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 718 | const Extension& extension) const { |
| 719 | bool was_installed_by_default = extension.was_installed_by_default(); |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 720 | #if defined(OS_CHROMEOS) |
| 721 | // On Chrome OS all external sources are controlled by us so it means that |
| 722 | // they are "default". Method was_installed_by_default returns false because |
| 723 | // extensions creation flags are ignored in case of default extensions with |
| 724 | // update URL(the flags aren't passed to OnExternalExtensionUpdateUrlFound). |
| 725 | // TODO(dpolukhin): remove this Chrome OS specific code as soon as creation |
| 726 | // flags are not ignored. |
| 727 | was_installed_by_default = |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 728 | extensions::Manifest::IsExternalLocation(extension.location()); |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 729 | #endif |
| 730 | // Note: Component extensions are protected from modification/uninstallation |
| 731 | // anyway, so there's no need to enforce them again for supervised users. |
| 732 | // Also, leave policy-installed extensions alone - they have their own |
| 733 | // management; in particular we don't want to override the force-install list. |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 734 | if (extensions::Manifest::IsComponentLocation(extension.location()) || |
| 735 | extensions::Manifest::IsPolicyLocation(extension.location()) || |
| 736 | extension.is_theme() || extension.from_bookmark() || |
| 737 | extension.is_shared_module() || was_installed_by_default) { |
| 738 | return ExtensionState::ALLOWED; |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 739 | } |
| 740 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 741 | if (extensions::util::WasInstalledByCustodian(extension.id(), profile_)) |
| 742 | return ExtensionState::FORCED; |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 743 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 744 | if (!base::FeatureList::IsEnabled( |
| 745 | supervised_users::kSupervisedUserInitiatedExtensionInstall)) { |
| 746 | return ExtensionState::BLOCKED; |
| 747 | } |
| 748 | |
| 749 | auto extension_it = approved_extensions_map_.find(extension.id()); |
| 750 | // If the installed version is approved, then the extension is allowed, |
| 751 | // otherwise, it requires approval. |
| 752 | if (extension_it != approved_extensions_map_.end() && |
Devlin Cronin | 03bf2d2 | 2017-12-20 08:21:05 | [diff] [blame] | 753 | extension_it->second == extension.version()) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 754 | return ExtensionState::ALLOWED; |
| 755 | } |
| 756 | return ExtensionState::REQUIRE_APPROVAL; |
mamir | 192d788 | 2016-06-22 17:10:16 | [diff] [blame] | 757 | } |
| 758 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 759 | std::string SupervisedUserService::GetDebugPolicyProviderName() const { |
| 760 | // Save the string space in official builds. |
Will Harris | 72a97a3 | 2018-05-29 19:05:21 | [diff] [blame] | 761 | #if DCHECK_IS_ON() |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 762 | return "Supervised User Service"; |
Will Harris | 72a97a3 | 2018-05-29 19:05:21 | [diff] [blame] | 763 | #else |
| 764 | IMMEDIATE_CRASH(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 765 | #endif |
| 766 | } |
| 767 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 768 | bool SupervisedUserService::UserMayLoad(const Extension* extension, |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 769 | base::string16* error) const { |
| 770 | DCHECK(ProfileIsSupervised()); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 771 | ExtensionState result = GetExtensionState(*extension); |
| 772 | bool may_load = result != ExtensionState::BLOCKED; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 773 | if (!may_load && error) |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 774 | *error = GetExtensionsLockedMessage(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 775 | return may_load; |
| 776 | } |
| 777 | |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 778 | bool SupervisedUserService::UserMayModifySettings(const Extension* extension, |
| 779 | base::string16* error) const { |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 780 | DCHECK(ProfileIsSupervised()); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 781 | ExtensionState result = GetExtensionState(*extension); |
| 782 | // While the following check allows the supervised user to modify the settings |
| 783 | // and enable or disable the extension, MustRemainDisabled properly takes care |
| 784 | // of keeping an extension disabled when required. |
| 785 | // For custodian-installed extensions, the state is always FORCED, even if |
| 786 | // it's waiting for an update approval. |
| 787 | bool may_modify = result != ExtensionState::FORCED; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 788 | if (!may_modify && error) |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 789 | *error = GetExtensionsLockedMessage(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 790 | return may_modify; |
| 791 | } |
| 792 | |
| 793 | // Note: Having MustRemainInstalled always say "true" for custodian-installed |
| 794 | // extensions does NOT prevent remote uninstalls (which is a bit unexpected, but |
| 795 | // exactly what we want). |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 796 | bool SupervisedUserService::MustRemainInstalled(const Extension* extension, |
| 797 | base::string16* error) const { |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 798 | DCHECK(ProfileIsSupervised()); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 799 | ExtensionState result = GetExtensionState(*extension); |
| 800 | bool may_not_uninstall = result == ExtensionState::FORCED; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 801 | if (may_not_uninstall && error) |
treib | 2170ea0 | 2015-10-13 14:55:12 | [diff] [blame] | 802 | *error = GetExtensionsLockedMessage(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 803 | return may_not_uninstall; |
| 804 | } |
| 805 | |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 806 | bool SupervisedUserService::MustRemainDisabled( |
| 807 | const Extension* extension, |
| 808 | extensions::disable_reason::DisableReason* reason, |
| 809 | base::string16* error) const { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 810 | DCHECK(ProfileIsSupervised()); |
| 811 | ExtensionState state = GetExtensionState(*extension); |
| 812 | // Only extensions that require approval should be disabled. |
| 813 | // Blocked extensions should be not loaded at all, and are taken care of |
| 814 | // at UserMayLoad. |
| 815 | bool must_remain_disabled = state == ExtensionState::REQUIRE_APPROVAL; |
| 816 | |
| 817 | if (must_remain_disabled) { |
| 818 | if (error) |
treib | 39ecc84 | 2016-11-17 12:07:07 | [diff] [blame] | 819 | *error = GetExtensionsLockedMessage(); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 820 | // If the extension must remain disabled due to permission increase, |
| 821 | // then the update request has been already sent at update time. |
| 822 | // We do nothing and we don't add an extra disable reason. |
| 823 | ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_); |
| 824 | if (extension_prefs->HasDisableReason( |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 825 | extension->id(), |
| 826 | extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE)) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 827 | if (reason) |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 828 | *reason = extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE; |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 829 | return true; |
| 830 | } |
| 831 | if (reason) |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 832 | *reason = extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED; |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 833 | if (base::FeatureList::IsEnabled( |
| 834 | supervised_users::kSupervisedUserInitiatedExtensionInstall)) { |
| 835 | // If the Extension isn't pending a custodian approval already, send |
| 836 | // an approval request. |
| 837 | if (!extension_prefs->HasDisableReason( |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 838 | extension->id(), extensions::disable_reason:: |
| 839 | DISABLE_CUSTODIAN_APPROVAL_REQUIRED)) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 840 | // MustRemainDisabled is a const method and hence cannot call |
| 841 | // AddExtensionInstallRequest directly. |
| 842 | SupervisedUserService* supervised_user_service = |
| 843 | SupervisedUserServiceFactory::GetForProfile(profile_); |
| 844 | supervised_user_service->AddExtensionInstallRequest( |
Devlin Cronin | 03bf2d2 | 2017-12-20 08:21:05 | [diff] [blame] | 845 | extension->id(), extension->version()); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 846 | } |
| 847 | } |
| 848 | } |
| 849 | return must_remain_disabled; |
| 850 | } |
| 851 | |
| 852 | void SupervisedUserService::OnExtensionInstalled( |
| 853 | content::BrowserContext* browser_context, |
| 854 | const extensions::Extension* extension, |
| 855 | bool is_update) { |
| 856 | // This callback method is responsible for updating extension state and |
| 857 | // approved_extensions_map_ upon extension updates. |
| 858 | if (!is_update) |
| 859 | return; |
| 860 | |
| 861 | ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_); |
| 862 | const std::string& id = extension->id(); |
Devlin Cronin | 03bf2d2 | 2017-12-20 08:21:05 | [diff] [blame] | 863 | const base::Version& version = extension->version(); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 864 | |
| 865 | // If an already approved extension is updated without requiring |
| 866 | // new permissions, we update the approved_version. |
| 867 | if (!extension_prefs->HasDisableReason( |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 868 | id, extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE) && |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 869 | approved_extensions_map_.count(id) > 0 && |
| 870 | approved_extensions_map_[id] < version) { |
| 871 | approved_extensions_map_[id] = version; |
| 872 | |
| 873 | std::string key = SupervisedUserSettingsService::MakeSplitSettingKey( |
| 874 | supervised_users::kApprovedExtensions, id); |
| 875 | std::unique_ptr<base::Value> version_value( |
jdoerrie | 122c4da | 2017-03-06 11:12:04 | [diff] [blame] | 876 | new base::Value(version.GetString())); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 877 | GetSettingsService()->UpdateSetting(key, std::move(version_value)); |
| 878 | } |
| 879 | // Upon extension update, the approved version may (or may not) match the |
| 880 | // installed one. Therefore, a change in extension state might be required. |
| 881 | ChangeExtensionStateIfNecessary(id); |
| 882 | } |
| 883 | |
| 884 | void SupervisedUserService::UpdateApprovedExtensions() { |
| 885 | const base::DictionaryValue* dict = profile_->GetPrefs()->GetDictionary( |
| 886 | prefs::kSupervisedUserApprovedExtensions); |
| 887 | // Keep track of currently approved extensions. We may need to disable them if |
| 888 | // they are not in the approved map anymore. |
| 889 | std::set<std::string> extensions_to_be_checked; |
| 890 | for (const auto& extension : approved_extensions_map_) |
| 891 | extensions_to_be_checked.insert(extension.first); |
| 892 | |
| 893 | approved_extensions_map_.clear(); |
| 894 | |
| 895 | for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { |
| 896 | std::string version_str; |
| 897 | bool result = it.value().GetAsString(&version_str); |
| 898 | DCHECK(result); |
| 899 | base::Version version(version_str); |
| 900 | if (version.IsValid()) { |
| 901 | approved_extensions_map_[it.key()] = version; |
| 902 | extensions_to_be_checked.insert(it.key()); |
| 903 | } else { |
| 904 | LOG(WARNING) << "Invalid version number " << version_str; |
| 905 | } |
| 906 | } |
| 907 | |
| 908 | for (const auto& extension_id : extensions_to_be_checked) { |
| 909 | ChangeExtensionStateIfNecessary(extension_id); |
| 910 | } |
| 911 | } |
| 912 | |
| 913 | void SupervisedUserService::ChangeExtensionStateIfNecessary( |
| 914 | const std::string& extension_id) { |
| 915 | ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| 916 | const Extension* extension = registry->GetInstalledExtension(extension_id); |
| 917 | // If the extension is not installed (yet), do nothing. |
| 918 | // Things will be handled after installation. |
| 919 | if (!extension) |
| 920 | return; |
| 921 | |
| 922 | ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_); |
Devlin Cronin | 464a267 | 2018-05-31 08:52:46 | [diff] [blame] | 923 | extensions::ExtensionService* service = |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 924 | ExtensionSystem::Get(profile_)->extension_service(); |
| 925 | |
| 926 | ExtensionState state = GetExtensionState(*extension); |
| 927 | switch (state) { |
| 928 | // BLOCKED/FORCED extensions should be already disabled/enabled |
| 929 | // and we don't need to change their state here. |
| 930 | case ExtensionState::BLOCKED: |
| 931 | case ExtensionState::FORCED: |
| 932 | break; |
| 933 | case ExtensionState::REQUIRE_APPROVAL: |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 934 | service->DisableExtension( |
| 935 | extension_id, |
| 936 | extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 937 | break; |
| 938 | case ExtensionState::ALLOWED: |
| 939 | extension_prefs->RemoveDisableReason( |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 940 | extension_id, |
| 941 | extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 942 | extension_prefs->RemoveDisableReason( |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 943 | extension_id, |
| 944 | extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE); |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 945 | // If not disabled for other reasons, enable it. |
| 946 | if (extension_prefs->GetDisableReasons(extension_id) == |
Minh X. Nguyen | 4547901 | 2017-08-18 21:35:36 | [diff] [blame] | 947 | extensions::disable_reason::DISABLE_NONE) { |
mamir | e960964 | 2016-06-28 22:17:54 | [diff] [blame] | 948 | service->EnableExtension(extension_id); |
| 949 | } |
| 950 | break; |
| 951 | } |
| 952 | } |
| 953 | |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 954 | void SupervisedUserService::SetExtensionsActive() { |
| 955 | extensions::ExtensionSystem* extension_system = |
| 956 | extensions::ExtensionSystem::Get(profile_); |
| 957 | extensions::ManagementPolicy* management_policy = |
| 958 | extension_system->management_policy(); |
| 959 | |
| 960 | if (management_policy) { |
| 961 | if (active_) |
| 962 | management_policy->RegisterProvider(this); |
| 963 | else |
| 964 | management_policy->UnregisterProvider(this); |
| 965 | |
| 966 | // Re-check the policy to make sure any new settings get applied. |
| 967 | extension_system->extension_service()->CheckManagementPolicy(); |
| 968 | } |
| 969 | } |
brettw | 00899e6 | 2016-11-12 02:10:17 | [diff] [blame] | 970 | #endif // BUILDFLAG(ENABLE_EXTENSIONS) |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 971 | |
Marc Treib | cf85fa3 | 2018-11-19 15:28:19 | [diff] [blame] | 972 | syncer::ModelTypeSet SupervisedUserService::GetForcedDataTypes() const { |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 973 | if (!ProfileIsSupervised()) |
| 974 | return syncer::ModelTypeSet(); |
| 975 | |
| 976 | syncer::ModelTypeSet result; |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 977 | result.Put(syncer::EXTENSIONS); |
| 978 | result.Put(syncer::EXTENSION_SETTINGS); |
| 979 | result.Put(syncer::APPS); |
| 980 | result.Put(syncer::APP_SETTINGS); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 981 | result.Put(syncer::APP_LIST); |
Maksim Moskvitin | 62c0e45 | 2019-04-11 12:01:00 | [diff] [blame] | 982 | result.Put(syncer::ARC_PACKAGE); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 983 | return result; |
| 984 | } |
| 985 | |
Marc Treib | b3bbf1d2 | 2019-03-27 15:45:39 | [diff] [blame] | 986 | bool SupervisedUserService::IsEncryptEverythingAllowed() const { |
| 987 | return !active_; |
| 988 | } |
| 989 | |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 990 | #if !defined(OS_ANDROID) |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 991 | void SupervisedUserService::OnBrowserSetLastActive(Browser* browser) { |
| 992 | bool profile_became_active = profile_->IsSameProfile(browser->profile()); |
| 993 | if (!is_profile_active_ && profile_became_active) |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 994 | base::RecordAction(UserMetricsAction("ManagedUsers_OpenProfile")); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 995 | else if (is_profile_active_ && !profile_became_active) |
bratell | 0a7406f | 2017-03-28 07:46:37 | [diff] [blame] | 996 | base::RecordAction(UserMetricsAction("ManagedUsers_SwitchProfile")); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 997 | |
| 998 | is_profile_active_ = profile_became_active; |
| 999 | } |
jam | 1c5a9149 | 2016-02-24 20:47:53 | [diff] [blame] | 1000 | #endif // !defined(OS_ANDROID) |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 1001 | |
| 1002 | void SupervisedUserService::OnSiteListUpdated() { |
ericwilligers | 8b92b05 | 2016-10-19 22:21:58 | [diff] [blame] | 1003 | for (SupervisedUserServiceObserver& observer : observer_list_) |
| 1004 | observer.OnURLFilterChanged(); |
bauerb | 5f8cda9 | 2015-10-07 15:36:44 | [diff] [blame] | 1005 | } |