1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/supervised_user/supervised_user_whitelist_service.h"
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/user_metrics.h"
12 #include "base/metrics/user_metrics_action.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/values.h"
16 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
17 #include "chrome/browser/supervised_user/supervised_user_site_list.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "sync/api/sync_change.h"
21 #include "sync/api/sync_data.h"
22 #include "sync/api/sync_error.h"
23 #include "sync/api/sync_error_factory.h"
24 #include "sync/api/sync_merge_result.h"
25 #include "sync/protocol/sync.pb.h"
27 const char kName
[] = "name";
29 SupervisedUserWhitelistService::SupervisedUserWhitelistService(
31 component_updater::SupervisedUserWhitelistInstaller
* installer
,
32 const std::string
& client_id
)
34 installer_(installer
),
35 client_id_(client_id
),
36 weak_ptr_factory_(this) {
40 SupervisedUserWhitelistService::~SupervisedUserWhitelistService() {
44 void SupervisedUserWhitelistService::RegisterProfilePrefs(
45 user_prefs::PrefRegistrySyncable
* registry
) {
46 registry
->RegisterDictionaryPref(
47 prefs::kSupervisedUserWhitelists
,
48 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
51 void SupervisedUserWhitelistService::Init() {
52 const base::DictionaryValue
* whitelists
=
53 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
54 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
56 registered_whitelists_
.insert(it
.key());
58 UMA_HISTOGRAM_COUNTS_100("ManagedUsers.Whitelist.Count", whitelists
->size());
60 // The installer can be null in some unit tests.
64 installer_
->Subscribe(
65 base::Bind(&SupervisedUserWhitelistService::OnWhitelistReady
,
66 weak_ptr_factory_
.GetWeakPtr()));
69 void SupervisedUserWhitelistService::AddSiteListsChangedCallback(
70 const SiteListsChangedCallback
& callback
) {
71 site_lists_changed_callbacks_
.push_back(callback
);
73 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
74 GetLoadedWhitelists(&whitelists
);
75 callback
.Run(whitelists
);
78 void SupervisedUserWhitelistService::LoadWhitelistForTesting(
79 const std::string
& id
,
80 const base::FilePath
& path
) {
81 bool result
= registered_whitelists_
.insert(id
).second
;
83 OnWhitelistReady(id
, path
);
86 void SupervisedUserWhitelistService::UnloadWhitelist(const std::string
& id
) {
87 bool result
= registered_whitelists_
.erase(id
) > 0u;
89 loaded_whitelists_
.erase(id
);
90 NotifyWhitelistsChanged();
94 syncer::SyncData
SupervisedUserWhitelistService::CreateWhitelistSyncData(
95 const std::string
& id
,
96 const std::string
& name
) {
97 sync_pb::EntitySpecifics specifics
;
98 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
99 specifics
.mutable_managed_user_whitelist();
100 whitelist
->set_id(id
);
101 whitelist
->set_name(name
);
103 return syncer::SyncData::CreateLocalData(id
, name
, specifics
);
106 syncer::SyncMergeResult
107 SupervisedUserWhitelistService::MergeDataAndStartSyncing(
108 syncer::ModelType type
,
109 const syncer::SyncDataList
& initial_sync_data
,
110 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor
,
111 scoped_ptr
<syncer::SyncErrorFactory
> error_handler
) {
112 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
114 syncer::SyncChangeList change_list
;
115 syncer::SyncMergeResult
result(syncer::SUPERVISED_USER_WHITELISTS
);
117 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
118 base::DictionaryValue
* pref_dict
= update
.Get();
119 result
.set_num_items_before_association(pref_dict
->size());
120 std::set
<std::string
> seen_ids
;
121 int num_items_added
= 0;
122 int num_items_modified
= 0;
124 for (const syncer::SyncData
& sync_data
: initial_sync_data
) {
125 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, sync_data
.GetDataType());
126 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
127 sync_data
.GetSpecifics().managed_user_whitelist();
128 std::string id
= whitelist
.id();
129 std::string name
= whitelist
.name();
131 base::DictionaryValue
* dict
= nullptr;
132 if (pref_dict
->GetDictionary(id
, &dict
)) {
133 std::string old_name
;
134 bool result
= dict
->GetString(kName
, &old_name
);
136 if (name
!= old_name
) {
137 SetWhitelistProperties(dict
, whitelist
);
138 num_items_modified
++;
142 AddNewWhitelist(pref_dict
, whitelist
);
146 std::set
<std::string
> ids_to_remove
;
147 for (base::DictionaryValue::Iterator
it(*pref_dict
); !it
.IsAtEnd();
149 if (seen_ids
.find(it
.key()) == seen_ids
.end())
150 ids_to_remove
.insert(it
.key());
153 for (const std::string
& id
: ids_to_remove
)
154 RemoveWhitelist(pref_dict
, id
);
156 // Notify if whitelists have been uninstalled. We will notify about newly
157 // added whitelists later, when they are actually available
158 // (in OnWhitelistLoaded).
159 if (!ids_to_remove
.empty())
160 NotifyWhitelistsChanged();
162 result
.set_num_items_added(num_items_added
);
163 result
.set_num_items_modified(num_items_modified
);
164 result
.set_num_items_deleted(ids_to_remove
.size());
165 result
.set_num_items_after_association(pref_dict
->size());
169 void SupervisedUserWhitelistService::StopSyncing(syncer::ModelType type
) {
170 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
173 syncer::SyncDataList
SupervisedUserWhitelistService::GetAllSyncData(
174 syncer::ModelType type
) const {
175 syncer::SyncDataList sync_data
;
176 const base::DictionaryValue
* whitelists
=
177 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
178 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
180 const std::string
& id
= it
.key();
181 const base::DictionaryValue
* dict
= nullptr;
182 it
.value().GetAsDictionary(&dict
);
184 bool result
= dict
->GetString(kName
, &name
);
186 sync_pb::EntitySpecifics specifics
;
187 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
188 specifics
.mutable_managed_user_whitelist();
189 whitelist
->set_id(id
);
190 whitelist
->set_name(name
);
191 sync_data
.push_back(syncer::SyncData::CreateLocalData(id
, name
, specifics
));
196 syncer::SyncError
SupervisedUserWhitelistService::ProcessSyncChanges(
197 const tracked_objects::Location
& from_here
,
198 const syncer::SyncChangeList
& change_list
) {
199 bool whitelists_removed
= false;
200 syncer::SyncError error
;
201 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
202 base::DictionaryValue
* pref_dict
= update
.Get();
203 for (const syncer::SyncChange
& sync_change
: change_list
) {
204 syncer::SyncData data
= sync_change
.sync_data();
205 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, data
.GetDataType());
206 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
207 data
.GetSpecifics().managed_user_whitelist();
208 std::string id
= whitelist
.id();
209 switch (sync_change
.change_type()) {
210 case syncer::SyncChange::ACTION_ADD
: {
211 DCHECK(!pref_dict
->HasKey(id
)) << id
;
212 AddNewWhitelist(pref_dict
, whitelist
);
215 case syncer::SyncChange::ACTION_UPDATE
: {
216 base::DictionaryValue
* dict
= nullptr;
217 pref_dict
->GetDictionaryWithoutPathExpansion(id
, &dict
);
218 SetWhitelistProperties(dict
, whitelist
);
221 case syncer::SyncChange::ACTION_DELETE
: {
222 DCHECK(pref_dict
->HasKey(id
)) << id
;
223 RemoveWhitelist(pref_dict
, id
);
224 whitelists_removed
= true;
227 case syncer::SyncChange::ACTION_INVALID
: {
234 if (whitelists_removed
)
235 NotifyWhitelistsChanged();
240 void SupervisedUserWhitelistService::AddNewWhitelist(
241 base::DictionaryValue
* pref_dict
,
242 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
243 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Added"));
245 bool new_installation
= true;
246 RegisterWhitelist(whitelist
.id(), whitelist
.name(), new_installation
);
247 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
248 SetWhitelistProperties(dict
.get(), whitelist
);
249 pref_dict
->SetWithoutPathExpansion(whitelist
.id(), dict
.release());
252 void SupervisedUserWhitelistService::SetWhitelistProperties(
253 base::DictionaryValue
* dict
,
254 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
255 dict
->SetString(kName
, whitelist
.name());
258 void SupervisedUserWhitelistService::RemoveWhitelist(
259 base::DictionaryValue
* pref_dict
,
260 const std::string
& id
) {
261 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Removed"));
263 pref_dict
->RemoveWithoutPathExpansion(id
, NULL
);
264 installer_
->UnregisterWhitelist(client_id_
, id
);
268 void SupervisedUserWhitelistService::RegisterWhitelist(const std::string
& id
,
269 const std::string
& name
,
270 bool new_installation
) {
271 bool result
= registered_whitelists_
.insert(id
).second
;
274 installer_
->RegisterWhitelist(client_id_
, id
, name
);
277 void SupervisedUserWhitelistService::GetLoadedWhitelists(
278 std::vector
<scoped_refptr
<SupervisedUserSiteList
>>* whitelists
) {
279 for (const auto& whitelist
: loaded_whitelists_
)
280 whitelists
->push_back(whitelist
.second
);
283 void SupervisedUserWhitelistService::NotifyWhitelistsChanged() {
284 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
285 GetLoadedWhitelists(&whitelists
);
287 for (const auto& callback
: site_lists_changed_callbacks_
)
288 callback
.Run(whitelists
);
291 void SupervisedUserWhitelistService::OnWhitelistReady(
292 const std::string
& id
,
293 const base::FilePath
& whitelist_path
) {
294 // If we did not register the whitelist or it has been unregistered in the
295 // mean time, ignore it.
296 if (registered_whitelists_
.count(id
) == 0u)
299 SupervisedUserSiteList::Load(
301 base::Bind(&SupervisedUserWhitelistService::OnWhitelistLoaded
,
302 weak_ptr_factory_
.GetWeakPtr(), id
, base::TimeTicks::Now()));
305 void SupervisedUserWhitelistService::OnWhitelistLoaded(
306 const std::string
& id
,
307 base::TimeTicks start_time
,
308 const scoped_refptr
<SupervisedUserSiteList
>& whitelist
) {
310 LOG(WARNING
) << "Couldn't load whitelist " << id
;
314 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.TotalLoadDuration",
315 base::TimeTicks::Now() - start_time
);
317 // If the whitelist has been unregistered in the mean time, ignore it.
318 if (registered_whitelists_
.count(id
) == 0u)
321 loaded_whitelists_
[id
] = whitelist
;
322 NotifyWhitelistsChanged();