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