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/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/metrics/histogram.h"
12 #include "base/metrics/user_metrics.h"
13 #include "base/metrics/user_metrics_action.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h"
16 #include "base/strings/string_split.h"
17 #include "base/values.h"
18 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
19 #include "chrome/browser/supervised_user/supervised_user_site_list.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "sync/api/sync_change.h"
24 #include "sync/api/sync_data.h"
25 #include "sync/api/sync_error.h"
26 #include "sync/api/sync_error_factory.h"
27 #include "sync/api/sync_merge_result.h"
28 #include "sync/protocol/sync.pb.h"
30 const char kName
[] = "name";
32 SupervisedUserWhitelistService::SupervisedUserWhitelistService(
34 component_updater::SupervisedUserWhitelistInstaller
* installer
,
35 const std::string
& client_id
)
37 installer_(installer
),
38 client_id_(client_id
),
39 weak_ptr_factory_(this) {
43 SupervisedUserWhitelistService::~SupervisedUserWhitelistService() {
47 void SupervisedUserWhitelistService::RegisterProfilePrefs(
48 user_prefs::PrefRegistrySyncable
* registry
) {
49 registry
->RegisterDictionaryPref(prefs::kSupervisedUserWhitelists
);
52 void SupervisedUserWhitelistService::Init() {
53 const base::DictionaryValue
* whitelists
=
54 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
55 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
57 registered_whitelists_
.insert(it
.key());
59 UMA_HISTOGRAM_COUNTS_100("ManagedUsers.Whitelist.Count", whitelists
->size());
61 // The installer can be null in some unit tests.
65 installer_
->Subscribe(
66 base::Bind(&SupervisedUserWhitelistService::OnWhitelistReady
,
67 weak_ptr_factory_
.GetWeakPtr()));
69 // Register whitelists specified on the command line.
70 const base::CommandLine
* command_line
=
71 base::CommandLine::ForCurrentProcess();
72 std::string command_line_whitelists
= command_line
->GetSwitchValueASCII(
73 switches::kInstallSupervisedUserWhitelists
);
74 for (const base::StringPiece
& whitelist
: base::SplitStringPiece(
75 command_line_whitelists
, ",",
76 base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
)) {
79 size_t separator
= whitelist
.find(':');
80 if (separator
!= base::StringPiece::npos
) {
81 whitelist
.substr(0, separator
).CopyToString(&id
);
82 whitelist
.substr(separator
+ 1).CopyToString(&name
);
84 whitelist
.CopyToString(&id
);
87 // Skip whitelists that were already registered.
88 if (registered_whitelists_
.count(id
) > 0u)
91 bool new_installation
= true;
92 RegisterWhitelist(id
, name
, new_installation
);
96 void SupervisedUserWhitelistService::AddSiteListsChangedCallback(
97 const SiteListsChangedCallback
& callback
) {
98 site_lists_changed_callbacks_
.push_back(callback
);
100 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
101 GetLoadedWhitelists(&whitelists
);
102 callback
.Run(whitelists
);
105 void SupervisedUserWhitelistService::LoadWhitelistForTesting(
106 const std::string
& id
,
107 const base::FilePath
& path
) {
108 bool result
= registered_whitelists_
.insert(id
).second
;
110 OnWhitelistReady(id
, path
);
113 void SupervisedUserWhitelistService::UnloadWhitelist(const std::string
& id
) {
114 bool result
= registered_whitelists_
.erase(id
) > 0u;
116 loaded_whitelists_
.erase(id
);
117 NotifyWhitelistsChanged();
121 syncer::SyncData
SupervisedUserWhitelistService::CreateWhitelistSyncData(
122 const std::string
& id
,
123 const std::string
& name
) {
124 sync_pb::EntitySpecifics specifics
;
125 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
126 specifics
.mutable_managed_user_whitelist();
127 whitelist
->set_id(id
);
128 whitelist
->set_name(name
);
130 return syncer::SyncData::CreateLocalData(id
, name
, specifics
);
133 syncer::SyncMergeResult
134 SupervisedUserWhitelistService::MergeDataAndStartSyncing(
135 syncer::ModelType type
,
136 const syncer::SyncDataList
& initial_sync_data
,
137 scoped_ptr
<syncer::SyncChangeProcessor
> sync_processor
,
138 scoped_ptr
<syncer::SyncErrorFactory
> error_handler
) {
139 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
141 syncer::SyncChangeList change_list
;
142 syncer::SyncMergeResult
result(syncer::SUPERVISED_USER_WHITELISTS
);
144 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
145 base::DictionaryValue
* pref_dict
= update
.Get();
146 result
.set_num_items_before_association(pref_dict
->size());
147 std::set
<std::string
> seen_ids
;
148 int num_items_added
= 0;
149 int num_items_modified
= 0;
151 for (const syncer::SyncData
& sync_data
: initial_sync_data
) {
152 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, sync_data
.GetDataType());
153 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
154 sync_data
.GetSpecifics().managed_user_whitelist();
155 std::string id
= whitelist
.id();
156 std::string name
= whitelist
.name();
158 base::DictionaryValue
* dict
= nullptr;
159 if (pref_dict
->GetDictionary(id
, &dict
)) {
160 std::string old_name
;
161 bool result
= dict
->GetString(kName
, &old_name
);
163 if (name
!= old_name
) {
164 SetWhitelistProperties(dict
, whitelist
);
165 num_items_modified
++;
169 AddNewWhitelist(pref_dict
, whitelist
);
173 std::set
<std::string
> ids_to_remove
;
174 for (base::DictionaryValue::Iterator
it(*pref_dict
); !it
.IsAtEnd();
176 if (seen_ids
.find(it
.key()) == seen_ids
.end())
177 ids_to_remove
.insert(it
.key());
180 for (const std::string
& id
: ids_to_remove
)
181 RemoveWhitelist(pref_dict
, id
);
183 // Notify if whitelists have been uninstalled. We will notify about newly
184 // added whitelists later, when they are actually available
185 // (in OnWhitelistLoaded).
186 if (!ids_to_remove
.empty())
187 NotifyWhitelistsChanged();
189 result
.set_num_items_added(num_items_added
);
190 result
.set_num_items_modified(num_items_modified
);
191 result
.set_num_items_deleted(ids_to_remove
.size());
192 result
.set_num_items_after_association(pref_dict
->size());
196 void SupervisedUserWhitelistService::StopSyncing(syncer::ModelType type
) {
197 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, type
);
200 syncer::SyncDataList
SupervisedUserWhitelistService::GetAllSyncData(
201 syncer::ModelType type
) const {
202 syncer::SyncDataList sync_data
;
203 const base::DictionaryValue
* whitelists
=
204 prefs_
->GetDictionary(prefs::kSupervisedUserWhitelists
);
205 for (base::DictionaryValue::Iterator
it(*whitelists
); !it
.IsAtEnd();
207 const std::string
& id
= it
.key();
208 const base::DictionaryValue
* dict
= nullptr;
209 it
.value().GetAsDictionary(&dict
);
211 bool result
= dict
->GetString(kName
, &name
);
213 sync_pb::EntitySpecifics specifics
;
214 sync_pb::ManagedUserWhitelistSpecifics
* whitelist
=
215 specifics
.mutable_managed_user_whitelist();
216 whitelist
->set_id(id
);
217 whitelist
->set_name(name
);
218 sync_data
.push_back(syncer::SyncData::CreateLocalData(id
, name
, specifics
));
223 syncer::SyncError
SupervisedUserWhitelistService::ProcessSyncChanges(
224 const tracked_objects::Location
& from_here
,
225 const syncer::SyncChangeList
& change_list
) {
226 bool whitelists_removed
= false;
227 syncer::SyncError error
;
228 DictionaryPrefUpdate
update(prefs_
, prefs::kSupervisedUserWhitelists
);
229 base::DictionaryValue
* pref_dict
= update
.Get();
230 for (const syncer::SyncChange
& sync_change
: change_list
) {
231 syncer::SyncData data
= sync_change
.sync_data();
232 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS
, data
.GetDataType());
233 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
=
234 data
.GetSpecifics().managed_user_whitelist();
235 std::string id
= whitelist
.id();
236 switch (sync_change
.change_type()) {
237 case syncer::SyncChange::ACTION_ADD
: {
238 DCHECK(!pref_dict
->HasKey(id
)) << id
;
239 AddNewWhitelist(pref_dict
, whitelist
);
242 case syncer::SyncChange::ACTION_UPDATE
: {
243 base::DictionaryValue
* dict
= nullptr;
244 pref_dict
->GetDictionaryWithoutPathExpansion(id
, &dict
);
245 SetWhitelistProperties(dict
, whitelist
);
248 case syncer::SyncChange::ACTION_DELETE
: {
249 DCHECK(pref_dict
->HasKey(id
)) << id
;
250 RemoveWhitelist(pref_dict
, id
);
251 whitelists_removed
= true;
254 case syncer::SyncChange::ACTION_INVALID
: {
261 if (whitelists_removed
)
262 NotifyWhitelistsChanged();
267 void SupervisedUserWhitelistService::AddNewWhitelist(
268 base::DictionaryValue
* pref_dict
,
269 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
270 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Added"));
272 bool new_installation
= true;
273 RegisterWhitelist(whitelist
.id(), whitelist
.name(), new_installation
);
274 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
275 SetWhitelistProperties(dict
.get(), whitelist
);
276 pref_dict
->SetWithoutPathExpansion(whitelist
.id(), dict
.release());
279 void SupervisedUserWhitelistService::SetWhitelistProperties(
280 base::DictionaryValue
* dict
,
281 const sync_pb::ManagedUserWhitelistSpecifics
& whitelist
) {
282 dict
->SetString(kName
, whitelist
.name());
285 void SupervisedUserWhitelistService::RemoveWhitelist(
286 base::DictionaryValue
* pref_dict
,
287 const std::string
& id
) {
288 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Removed"));
290 pref_dict
->RemoveWithoutPathExpansion(id
, NULL
);
291 installer_
->UnregisterWhitelist(client_id_
, id
);
295 void SupervisedUserWhitelistService::RegisterWhitelist(const std::string
& id
,
296 const std::string
& name
,
297 bool new_installation
) {
298 bool result
= registered_whitelists_
.insert(id
).second
;
301 installer_
->RegisterWhitelist(client_id_
, id
, name
);
304 void SupervisedUserWhitelistService::GetLoadedWhitelists(
305 std::vector
<scoped_refptr
<SupervisedUserSiteList
>>* whitelists
) {
306 for (const auto& whitelist
: loaded_whitelists_
)
307 whitelists
->push_back(whitelist
.second
);
310 void SupervisedUserWhitelistService::NotifyWhitelistsChanged() {
311 std::vector
<scoped_refptr
<SupervisedUserSiteList
>> whitelists
;
312 GetLoadedWhitelists(&whitelists
);
314 for (const auto& callback
: site_lists_changed_callbacks_
)
315 callback
.Run(whitelists
);
318 void SupervisedUserWhitelistService::OnWhitelistReady(
319 const std::string
& id
,
320 const base::FilePath
& whitelist_path
) {
321 // If we did not register the whitelist or it has been unregistered in the
322 // mean time, ignore it.
323 if (registered_whitelists_
.count(id
) == 0u)
326 SupervisedUserSiteList::Load(
328 base::Bind(&SupervisedUserWhitelistService::OnWhitelistLoaded
,
329 weak_ptr_factory_
.GetWeakPtr(), id
, base::TimeTicks::Now()));
332 void SupervisedUserWhitelistService::OnWhitelistLoaded(
333 const std::string
& id
,
334 base::TimeTicks start_time
,
335 const scoped_refptr
<SupervisedUserSiteList
>& whitelist
) {
337 LOG(WARNING
) << "Couldn't load whitelist " << id
;
341 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.TotalLoadDuration",
342 base::TimeTicks::Now() - start_time
);
344 // If the whitelist has been unregistered in the mean time, ignore it.
345 if (registered_whitelists_
.count(id
) == 0u)
348 loaded_whitelists_
[id
] = whitelist
;
349 NotifyWhitelistsChanged();