ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_whitelist_service.cc
blobc688abe35f3bed99174dcad6b445349b4ce7410c
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"
7 #include <string>
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(
33 PrefService* prefs,
34 component_updater::SupervisedUserWhitelistInstaller* installer,
35 const std::string& client_id)
36 : prefs_(prefs),
37 installer_(installer),
38 client_id_(client_id),
39 weak_ptr_factory_(this) {
40 DCHECK(prefs);
43 SupervisedUserWhitelistService::~SupervisedUserWhitelistService() {
46 // static
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();
56 it.Advance()) {
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.
62 if (!installer_)
63 return;
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)) {
77 std::string id;
78 std::string name;
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);
83 } else {
84 whitelist.CopyToString(&id);
87 // Skip whitelists that were already registered.
88 if (registered_whitelists_.count(id) > 0u)
89 continue;
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;
109 DCHECK(result);
110 OnWhitelistReady(id, path);
113 void SupervisedUserWhitelistService::UnloadWhitelist(const std::string& id) {
114 bool result = registered_whitelists_.erase(id) > 0u;
115 DCHECK(result);
116 loaded_whitelists_.erase(id);
117 NotifyWhitelistsChanged();
120 // static
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();
157 seen_ids.insert(id);
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);
162 DCHECK(result);
163 if (name != old_name) {
164 SetWhitelistProperties(dict, whitelist);
165 num_items_modified++;
167 } else {
168 num_items_added++;
169 AddNewWhitelist(pref_dict, whitelist);
173 std::set<std::string> ids_to_remove;
174 for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
175 it.Advance()) {
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());
193 return result;
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();
206 it.Advance()) {
207 const std::string& id = it.key();
208 const base::DictionaryValue* dict = nullptr;
209 it.value().GetAsDictionary(&dict);
210 std::string name;
211 bool result = dict->GetString(kName, &name);
212 DCHECK(result);
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));
220 return sync_data;
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);
240 break;
242 case syncer::SyncChange::ACTION_UPDATE: {
243 base::DictionaryValue* dict = nullptr;
244 pref_dict->GetDictionaryWithoutPathExpansion(id, &dict);
245 SetWhitelistProperties(dict, whitelist);
246 break;
248 case syncer::SyncChange::ACTION_DELETE: {
249 DCHECK(pref_dict->HasKey(id)) << id;
250 RemoveWhitelist(pref_dict, id);
251 whitelists_removed = true;
252 break;
254 case syncer::SyncChange::ACTION_INVALID: {
255 NOTREACHED();
256 break;
261 if (whitelists_removed)
262 NotifyWhitelistsChanged();
264 return error;
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);
292 UnloadWhitelist(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;
299 DCHECK(result);
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)
324 return;
326 SupervisedUserSiteList::Load(
327 whitelist_path,
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) {
336 if (!whitelist) {
337 LOG(WARNING) << "Couldn't load whitelist " << id;
338 return;
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)
346 return;
348 loaded_whitelists_[id] = whitelist;
349 NotifyWhitelistsChanged();