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(prefs::kSupervisedUserWhitelists
);
49 void SupervisedUserWhitelistService::Init() {
50 const base::DictionaryValue
* whitelists
=
51 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
52 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
54 registered_whitelists_
.insert(it
.key());
56 UMA_HISTOGRAM_COUNTS_100("ManagedUsers.Whitelist.Count", whitelists
->size());
58 // The installer can be null in some unit tests.
62 installer_
->Subscribe(
63 base::Bind(&SupervisedUserWhitelistService::OnWhitelistReady
,
64 weak_ptr_factory_
.GetWeakPtr()));
67 void SupervisedUserWhitelistService::AddSiteListsChangedCallback(
68 const SiteListsChangedCallback
& callback
) {
69 site_lists_changed_callbacks_
.push_back(callback
);
71 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
72 GetLoadedWhitelists(&whitelists
);
73 callback
.Run(whitelists
);
76 void SupervisedUserWhitelistService::LoadWhitelistForTesting(
77 const std::string
& id
,
78 const base::FilePath
& path
) {
79 bool result
= registered_whitelists_
.insert(id
).second
;
81 OnWhitelistReady(id
, path
);
84 void SupervisedUserWhitelistService::UnloadWhitelist(const std::string
& id
) {
85 bool result
= registered_whitelists_
.erase(id
) > 0u;
87 loaded_whitelists_
.erase(id
);
88 NotifyWhitelistsChanged();
92 syncer::SyncData
SupervisedUserWhitelistService::CreateWhitelistSyncData(
93 const std::string
& id
,
94 const std::string
& name
) {
95 sync_pb::EntitySpecifics specifics
;
96 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
97 specifics
.mutable_managed_user_whitelist();
98 whitelist
->set_id(id
);
99 whitelist
->set_name(name
);
101 return syncer::SyncData::CreateLocalData(id
, name
, specifics
);
104 syncer::SyncMergeResult
105 SupervisedUserWhitelistService::MergeDataAndStartSyncing(
106 syncer::ModelType type
,
107 const syncer::SyncDataList
& initial_sync_data
,
108 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor
,
109 scoped_ptr
<syncer::SyncErrorFactory
> error_handler
) {
110 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
112 syncer::SyncChangeList change_list
;
113 syncer::SyncMergeResult
result(syncer::SUPERVISED_USER_WHITELISTS
);
115 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
116 base::DictionaryValue
* pref_dict
= update
.Get();
117 result
.set_num_items_before_association(pref_dict
->size());
118 std::set
<std::string
> seen_ids
;
119 int num_items_added
= 0;
120 int num_items_modified
= 0;
122 for (const syncer::SyncData
& sync_data
: initial_sync_data
) {
123 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, sync_data
.GetDataType());
124 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
125 sync_data
.GetSpecifics().managed_user_whitelist();
126 std::string id
= whitelist
.id();
127 std::string name
= whitelist
.name();
129 base::DictionaryValue
* dict
= nullptr;
130 if (pref_dict
->GetDictionary(id
, &dict
)) {
131 std::string old_name
;
132 bool result
= dict
->GetString(kName
, &old_name
);
134 if (name
!= old_name
) {
135 SetWhitelistProperties(dict
, whitelist
);
136 num_items_modified
++;
140 AddNewWhitelist(pref_dict
, whitelist
);
144 std::set
<std::string
> ids_to_remove
;
145 for (base::DictionaryValue::Iterator
it(*pref_dict
); !it
.IsAtEnd();
147 if (seen_ids
.find(it
.key()) == seen_ids
.end())
148 ids_to_remove
.insert(it
.key());
151 for (const std::string
& id
: ids_to_remove
)
152 RemoveWhitelist(pref_dict
, id
);
154 // Notify if whitelists have been uninstalled. We will notify about newly
155 // added whitelists later, when they are actually available
156 // (in OnWhitelistLoaded).
157 if (!ids_to_remove
.empty())
158 NotifyWhitelistsChanged();
160 result
.set_num_items_added(num_items_added
);
161 result
.set_num_items_modified(num_items_modified
);
162 result
.set_num_items_deleted(ids_to_remove
.size());
163 result
.set_num_items_after_association(pref_dict
->size());
167 void SupervisedUserWhitelistService::StopSyncing(syncer::ModelType type
) {
168 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
171 syncer::SyncDataList
SupervisedUserWhitelistService::GetAllSyncData(
172 syncer::ModelType type
) const {
173 syncer::SyncDataList sync_data
;
174 const base::DictionaryValue
* whitelists
=
175 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
176 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
178 const std::string
& id
= it
.key();
179 const base::DictionaryValue
* dict
= nullptr;
180 it
.value().GetAsDictionary(&dict
);
182 bool result
= dict
->GetString(kName
, &name
);
184 sync_pb::EntitySpecifics specifics
;
185 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
186 specifics
.mutable_managed_user_whitelist();
187 whitelist
->set_id(id
);
188 whitelist
->set_name(name
);
189 sync_data
.push_back(syncer::SyncData::CreateLocalData(id
, name
, specifics
));
194 syncer::SyncError
SupervisedUserWhitelistService::ProcessSyncChanges(
195 const tracked_objects::Location
& from_here
,
196 const syncer::SyncChangeList
& change_list
) {
197 bool whitelists_removed
= false;
198 syncer::SyncError error
;
199 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
200 base::DictionaryValue
* pref_dict
= update
.Get();
201 for (const syncer::SyncChange
& sync_change
: change_list
) {
202 syncer::SyncData data
= sync_change
.sync_data();
203 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, data
.GetDataType());
204 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
205 data
.GetSpecifics().managed_user_whitelist();
206 std::string id
= whitelist
.id();
207 switch (sync_change
.change_type()) {
208 case syncer::SyncChange::ACTION_ADD
: {
209 DCHECK(!pref_dict
->HasKey(id
)) << id
;
210 AddNewWhitelist(pref_dict
, whitelist
);
213 case syncer::SyncChange::ACTION_UPDATE
: {
214 base::DictionaryValue
* dict
= nullptr;
215 pref_dict
->GetDictionaryWithoutPathExpansion(id
, &dict
);
216 SetWhitelistProperties(dict
, whitelist
);
219 case syncer::SyncChange::ACTION_DELETE
: {
220 DCHECK(pref_dict
->HasKey(id
)) << id
;
221 RemoveWhitelist(pref_dict
, id
);
222 whitelists_removed
= true;
225 case syncer::SyncChange::ACTION_INVALID
: {
232 if (whitelists_removed
)
233 NotifyWhitelistsChanged();
238 void SupervisedUserWhitelistService::AddNewWhitelist(
239 base::DictionaryValue
* pref_dict
,
240 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
241 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Added"));
243 bool new_installation
= true;
244 RegisterWhitelist(whitelist
.id(), whitelist
.name(), new_installation
);
245 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
246 SetWhitelistProperties(dict
.get(), whitelist
);
247 pref_dict
->SetWithoutPathExpansion(whitelist
.id(), dict
.release());
250 void SupervisedUserWhitelistService::SetWhitelistProperties(
251 base::DictionaryValue
* dict
,
252 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
253 dict
->SetString(kName
, whitelist
.name());
256 void SupervisedUserWhitelistService::RemoveWhitelist(
257 base::DictionaryValue
* pref_dict
,
258 const std::string
& id
) {
259 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Removed"));
261 pref_dict
->RemoveWithoutPathExpansion(id
, NULL
);
262 installer_
->UnregisterWhitelist(client_id_
, id
);
266 void SupervisedUserWhitelistService::RegisterWhitelist(const std::string
& id
,
267 const std::string
& name
,
268 bool new_installation
) {
269 bool result
= registered_whitelists_
.insert(id
).second
;
272 installer_
->RegisterWhitelist(client_id_
, id
, name
);
275 void SupervisedUserWhitelistService::GetLoadedWhitelists(
276 std::vector
<scoped_refptr
<SupervisedUserSiteList
>>* whitelists
) {
277 for (const auto& whitelist
: loaded_whitelists_
)
278 whitelists
->push_back(whitelist
.second
);
281 void SupervisedUserWhitelistService::NotifyWhitelistsChanged() {
282 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
283 GetLoadedWhitelists(&whitelists
);
285 for (const auto& callback
: site_lists_changed_callbacks_
)
286 callback
.Run(whitelists
);
289 void SupervisedUserWhitelistService::OnWhitelistReady(
290 const std::string
& id
,
291 const base::FilePath
& whitelist_path
) {
292 // If we did not register the whitelist or it has been unregistered in the
293 // mean time, ignore it.
294 if (registered_whitelists_
.count(id
) == 0u)
297 SupervisedUserSiteList::Load(
299 base::Bind(&SupervisedUserWhitelistService::OnWhitelistLoaded
,
300 weak_ptr_factory_
.GetWeakPtr(), id
, base::TimeTicks::Now()));
303 void SupervisedUserWhitelistService::OnWhitelistLoaded(
304 const std::string
& id
,
305 base::TimeTicks start_time
,
306 const scoped_refptr
<SupervisedUserSiteList
>& whitelist
) {
308 LOG(WARNING
) << "Couldn't load whitelist " << id
;
312 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.TotalLoadDuration",
313 base::TimeTicks::Now() - start_time
);
315 // If the whitelist has been unregistered in the mean time, ignore it.
316 if (registered_whitelists_
.count(id
) == 0u)
319 loaded_whitelists_
[id
] = whitelist
;
320 NotifyWhitelistsChanged();