1 // Copyright 2013 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/managed_mode/managed_user_sync_service.h"
8 #include "base/callback.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/user_prefs/pref_registry_syncable.h"
16 #include "sync/api/sync_change.h"
17 #include "sync/api/sync_data.h"
18 #include "sync/api/sync_error.h"
19 #include "sync/api/sync_error_factory.h"
20 #include "sync/api/sync_merge_result.h"
21 #include "sync/protocol/sync.pb.h"
23 using base::DictionaryValue;
24 using user_prefs::PrefRegistrySyncable;
25 using syncer::MANAGED_USERS;
26 using syncer::ModelType;
27 using syncer::SyncChange;
28 using syncer::SyncChangeList;
29 using syncer::SyncChangeProcessor;
30 using syncer::SyncData;
31 using syncer::SyncDataList;
32 using syncer::SyncError;
33 using syncer::SyncErrorFactory;
34 using syncer::SyncMergeResult;
35 using sync_pb::ManagedUserSpecifics;
39 #if defined(OS_CHROMEOS)
40 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
42 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
45 SyncData CreateLocalSyncData(const std::string& id,
46 const std::string& name,
48 const std::string& master_key,
49 const std::string& chrome_avatar,
50 const std::string& chromeos_avatar) {
51 ::sync_pb::EntitySpecifics specifics;
52 specifics.mutable_managed_user()->set_id(id);
53 specifics.mutable_managed_user()->set_name(name);
54 if (!chrome_avatar.empty())
55 specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
57 specifics.mutable_managed_user()->clear_chrome_avatar();
58 if (!chromeos_avatar.empty())
59 specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
60 if (!master_key.empty())
61 specifics.mutable_managed_user()->set_master_key(master_key);
63 specifics.mutable_managed_user()->set_acknowledged(true);
64 return SyncData::CreateLocalData(id, name, specifics);
67 SyncData CreateSyncDataFromDictionaryEntry(
68 const DictionaryValue::Iterator& it) {
69 const DictionaryValue* dict = NULL;
70 bool success = it.value().GetAsDictionary(&dict);
72 bool acknowledged = false;
73 dict->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
75 dict->GetString(ManagedUserSyncService::kName, &name);
76 DCHECK(!name.empty());
77 std::string master_key;
78 dict->GetString(ManagedUserSyncService::kMasterKey, &master_key);
79 std::string chrome_avatar;
80 dict->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
81 std::string chromeos_avatar;
82 dict->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
84 return CreateLocalSyncData(it.key(), name, acknowledged, master_key,
85 chrome_avatar, chromeos_avatar);
90 const char ManagedUserSyncService::kAcknowledged[] = "acknowledged";
91 const char ManagedUserSyncService::kChromeAvatar[] = "chromeAvatar";
92 const char ManagedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
93 const char ManagedUserSyncService::kMasterKey[] = "masterKey";
94 const char ManagedUserSyncService::kName[] = "name";
95 const int ManagedUserSyncService::kNoAvatar = -100;
97 ManagedUserSyncService::ManagedUserSyncService(PrefService* prefs)
99 pref_change_registrar_.Init(prefs_);
100 pref_change_registrar_.Add(
101 prefs::kGoogleServicesLastUsername,
102 base::Bind(&ManagedUserSyncService::OnLastSignedInUsernameChange,
103 base::Unretained(this)));
106 ManagedUserSyncService::~ManagedUserSyncService() {
110 void ManagedUserSyncService::RegisterProfilePrefs(
111 PrefRegistrySyncable* registry) {
112 registry->RegisterDictionaryPref(prefs::kManagedUsers,
113 PrefRegistrySyncable::UNSYNCABLE_PREF);
117 bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
119 // TODO(ibraaaa): when chrome OS supports supervised users avatar syncing
120 // then update this method to support extracting the avatar index
121 // for chrome OS as well.
122 DCHECK(avatar_index);
123 if (avatar_str.empty()) {
124 *avatar_index = kNoAvatar;
127 #if defined(OS_CHROMEOS)
128 const char* prefix = kChromeOSAvatarPrefix;
130 const char* prefix = kChromeAvatarPrefix;
132 size_t prefix_len = strlen(prefix);
133 if (avatar_str.size() <= prefix_len ||
134 avatar_str.substr(0, prefix_len) != prefix) {
138 return base::StringToInt(avatar_str.substr(prefix_len), avatar_index);
142 std::string ManagedUserSyncService::BuildAvatarString(int avatar_index) {
143 #if defined(OS_CHROMEOS)
144 const char* prefix = kChromeOSAvatarPrefix;
146 const char* prefix = kChromeAvatarPrefix;
148 return base::StringPrintf("%s%d", prefix, avatar_index);
151 void ManagedUserSyncService::AddObserver(
152 ManagedUserSyncServiceObserver* observer) {
153 observers_.AddObserver(observer);
156 void ManagedUserSyncService::RemoveObserver(
157 ManagedUserSyncServiceObserver* observer) {
158 observers_.RemoveObserver(observer);
161 void ManagedUserSyncService::AddManagedUser(const std::string& id,
162 const std::string& name,
163 const std::string& master_key,
165 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
166 DictionaryValue* dict = update.Get();
167 DictionaryValue* value = new DictionaryValue;
168 value->SetString(kName, name);
169 value->SetString(kMasterKey, master_key);
170 std::string chrome_avatar;
171 std::string chromeos_avatar;
172 #if defined(OS_CHROMEOS)
173 chromeos_avatar = BuildAvatarString(avatar_index);
175 chrome_avatar = BuildAvatarString(avatar_index);
177 value->SetString(kChromeAvatar, chrome_avatar);
178 value->SetString(kChromeOsAvatar, chromeos_avatar);
179 DCHECK(!dict->HasKey(id));
180 dict->SetWithoutPathExpansion(id, value);
182 if (!sync_processor_)
185 // If we're already syncing, create a new change and upload it.
186 SyncChangeList change_list;
187 change_list.push_back(SyncChange(
189 SyncChange::ACTION_ADD,
190 CreateLocalSyncData(id, name, false, master_key,
191 chrome_avatar, chromeos_avatar)));
193 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
194 DCHECK(!error.IsSet()) << error.ToString();
197 void ManagedUserSyncService::DeleteManagedUser(const std::string& id) {
198 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
199 bool success = update->RemoveWithoutPathExpansion(id, NULL);
202 if (!sync_processor_)
205 SyncChangeList change_list;
206 change_list.push_back(SyncChange(
208 SyncChange::ACTION_DELETE,
209 SyncData::CreateLocalDelete(id, MANAGED_USERS)));
210 SyncError sync_error =
211 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
212 DCHECK(!sync_error.IsSet());
215 const DictionaryValue* ManagedUserSyncService::GetManagedUsers() {
216 DCHECK(sync_processor_);
217 return prefs_->GetDictionary(prefs::kManagedUsers);
220 bool ManagedUserSyncService::UpdateManagedUserAvatarIfNeeded(
221 const std::string& id,
223 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
224 DictionaryValue* dict = update.Get();
225 DCHECK(dict->HasKey(id));
226 DictionaryValue* value = NULL;
227 bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
230 bool acknowledged = false;
231 value->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
233 value->GetString(ManagedUserSyncService::kName, &name);
234 std::string master_key;
235 value->GetString(ManagedUserSyncService::kMasterKey, &master_key);
236 // TODO(ibraaaa): this should be updated when avatar syncing for
237 // supervised users is implemented on Chrome OS.
238 std::string chromeos_avatar;
239 value->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
240 std::string chrome_avatar;
241 value->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
242 if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
245 chrome_avatar = avatar_index == kNoAvatar ?
246 std::string() : BuildAvatarString(avatar_index);
247 value->SetString(kChromeAvatar, chrome_avatar);
249 if (!sync_processor_)
252 SyncChangeList change_list;
253 change_list.push_back(SyncChange(
255 SyncChange::ACTION_UPDATE,
256 CreateLocalSyncData(id, name, acknowledged, master_key,
257 chrome_avatar, chromeos_avatar)));
259 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
260 DCHECK(!error.IsSet()) << error.ToString();
264 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string& id) {
265 bool cleared = UpdateManagedUserAvatarIfNeeded(id, kNoAvatar);
269 void ManagedUserSyncService::GetManagedUsersAsync(
270 const ManagedUsersCallback& callback) {
271 // If we are already syncing, just run the callback.
272 if (sync_processor_) {
273 callback.Run(GetManagedUsers());
277 // Otherwise queue it up until we start syncing.
278 callbacks_.push_back(callback);
281 void ManagedUserSyncService::Shutdown() {
282 NotifyManagedUsersSyncingStopped();
285 SyncMergeResult ManagedUserSyncService::MergeDataAndStartSyncing(
287 const SyncDataList& initial_sync_data,
288 scoped_ptr<SyncChangeProcessor> sync_processor,
289 scoped_ptr<SyncErrorFactory> error_handler) {
290 DCHECK_EQ(MANAGED_USERS, type);
291 sync_processor_ = sync_processor.Pass();
292 error_handler_ = error_handler.Pass();
294 SyncChangeList change_list;
295 SyncMergeResult result(MANAGED_USERS);
297 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
298 DictionaryValue* dict = update.Get();
299 result.set_num_items_before_association(dict->size());
300 std::set<std::string> seen_ids;
301 int num_items_added = 0;
302 int num_items_modified = 0;
303 for (SyncDataList::const_iterator it = initial_sync_data.begin();
304 it != initial_sync_data.end(); ++it) {
305 DCHECK_EQ(MANAGED_USERS, it->GetDataType());
306 const ManagedUserSpecifics& managed_user =
307 it->GetSpecifics().managed_user();
308 DictionaryValue* value = new DictionaryValue();
309 value->SetString(kName, managed_user.name());
310 value->SetBoolean(kAcknowledged, managed_user.acknowledged());
311 value->SetString(kMasterKey, managed_user.master_key());
312 value->SetString(kChromeAvatar, managed_user.chrome_avatar());
313 value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
314 if (dict->HasKey(managed_user.id()))
315 num_items_modified++;
318 dict->SetWithoutPathExpansion(managed_user.id(), value);
319 seen_ids.insert(managed_user.id());
322 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
323 if (seen_ids.find(it.key()) != seen_ids.end())
326 change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD,
327 CreateSyncDataFromDictionaryEntry(it)));
329 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
331 result.set_num_items_modified(num_items_modified);
332 result.set_num_items_added(num_items_added);
333 result.set_num_items_after_association(dict->size());
340 void ManagedUserSyncService::StopSyncing(ModelType type) {
341 DCHECK_EQ(MANAGED_USERS, type);
342 // The observers may want to change the Sync data, so notify them before
343 // resetting the |sync_processor_|.
344 NotifyManagedUsersSyncingStopped();
345 sync_processor_.reset();
346 error_handler_.reset();
349 SyncDataList ManagedUserSyncService::GetAllSyncData(
350 ModelType type) const {
352 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
353 DictionaryValue* dict = update.Get();
354 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
355 data.push_back(CreateSyncDataFromDictionaryEntry(it));
360 SyncError ManagedUserSyncService::ProcessSyncChanges(
361 const tracked_objects::Location& from_here,
362 const SyncChangeList& change_list) {
364 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
365 DictionaryValue* dict = update.Get();
366 for (SyncChangeList::const_iterator it = change_list.begin();
367 it != change_list.end(); ++it) {
368 SyncData data = it->sync_data();
369 DCHECK_EQ(MANAGED_USERS, data.GetDataType());
370 const ManagedUserSpecifics& managed_user =
371 data.GetSpecifics().managed_user();
372 switch (it->change_type()) {
373 case SyncChange::ACTION_ADD:
374 case SyncChange::ACTION_UPDATE: {
375 // Every item we get from the server should be acknowledged.
376 DCHECK(managed_user.acknowledged());
377 const DictionaryValue* old_value = NULL;
378 dict->GetDictionaryWithoutPathExpansion(managed_user.id(), &old_value);
380 // For an update action, the managed user should already exist, for an
381 // add action, it should not.
383 old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
386 // If the managed user switched from unacknowledged to acknowledged,
387 // we might need to continue with a registration.
388 if (old_value && !old_value->HasKey(kAcknowledged))
389 NotifyManagedUserAcknowledged(managed_user.id());
391 DictionaryValue* value = new DictionaryValue;
392 value->SetString(kName, managed_user.name());
393 value->SetBoolean(kAcknowledged, managed_user.acknowledged());
394 value->SetString(kMasterKey, managed_user.master_key());
395 value->SetString(kChromeAvatar, managed_user.chrome_avatar());
396 value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
397 dict->SetWithoutPathExpansion(managed_user.id(), value);
400 case SyncChange::ACTION_DELETE: {
401 DCHECK(dict->HasKey(managed_user.id())) << managed_user.id();
402 dict->RemoveWithoutPathExpansion(managed_user.id(), NULL);
405 case SyncChange::ACTION_INVALID: {
414 void ManagedUserSyncService::OnLastSignedInUsernameChange() {
415 DCHECK(!sync_processor_);
417 // If the last signed in user changes, we clear all data, to avoid managed
418 // users from one custodian appearing in another one's profile.
419 prefs_->ClearPref(prefs::kManagedUsers);
422 void ManagedUserSyncService::NotifyManagedUserAcknowledged(
423 const std::string& managed_user_id) {
424 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
425 OnManagedUserAcknowledged(managed_user_id));
428 void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() {
429 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
430 OnManagedUsersSyncingStopped());
433 void ManagedUserSyncService::DispatchCallbacks() {
434 const DictionaryValue* managed_users =
435 prefs_->GetDictionary(prefs::kManagedUsers);
436 for (std::vector<ManagedUsersCallback>::iterator it = callbacks_.begin();
437 it != callbacks_.end(); ++it) {
438 it->Run(managed_users);