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/common/pref_names.h"
14 #include "components/user_prefs/pref_registry_syncable.h"
15 #include "sync/api/sync_change.h"
16 #include "sync/api/sync_data.h"
17 #include "sync/api/sync_error.h"
18 #include "sync/api/sync_error_factory.h"
19 #include "sync/api/sync_merge_result.h"
20 #include "sync/protocol/sync.pb.h"
22 using base::DictionaryValue
;
23 using user_prefs::PrefRegistrySyncable
;
24 using syncer::MANAGED_USERS
;
25 using syncer::ModelType
;
26 using syncer::SyncChange
;
27 using syncer::SyncChangeList
;
28 using syncer::SyncChangeProcessor
;
29 using syncer::SyncData
;
30 using syncer::SyncDataList
;
31 using syncer::SyncError
;
32 using syncer::SyncErrorFactory
;
33 using syncer::SyncMergeResult
;
34 using sync_pb::ManagedUserSpecifics
;
38 #if defined(OS_CHROMEOS)
39 const char kChromeOSAvatarPrefix
[] = "chromeos-avatar-index:";
41 const char kChromeAvatarPrefix
[] = "chrome-avatar-index:";
44 SyncData
CreateLocalSyncData(const std::string
& id
,
45 const std::string
& name
,
47 const std::string
& master_key
,
48 const std::string
& chrome_avatar
,
49 const std::string
& chromeos_avatar
) {
50 ::sync_pb::EntitySpecifics specifics
;
51 specifics
.mutable_managed_user()->set_id(id
);
52 specifics
.mutable_managed_user()->set_name(name
);
53 if (!chrome_avatar
.empty())
54 specifics
.mutable_managed_user()->set_chrome_avatar(chrome_avatar
);
55 if (!chromeos_avatar
.empty())
56 specifics
.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar
);
57 if (!master_key
.empty())
58 specifics
.mutable_managed_user()->set_master_key(master_key
);
60 specifics
.mutable_managed_user()->set_acknowledged(true);
61 return SyncData::CreateLocalData(id
, name
, specifics
);
64 SyncData
CreateSyncDataFromDictionaryEntry(
65 const base::DictionaryValue::Iterator
& it
) {
66 const base::DictionaryValue
* dict
= NULL
;
67 bool success
= it
.value().GetAsDictionary(&dict
);
69 bool acknowledged
= false;
70 dict
->GetBoolean(ManagedUserSyncService::kAcknowledged
, &acknowledged
);
72 dict
->GetString(ManagedUserSyncService::kName
, &name
);
73 DCHECK(!name
.empty());
74 std::string master_key
;
75 dict
->GetString(ManagedUserSyncService::kMasterKey
, &master_key
);
76 std::string chrome_avatar
;
77 dict
->GetString(ManagedUserSyncService::kChromeAvatar
, &chrome_avatar
);
78 std::string chromeos_avatar
;
79 dict
->GetString(ManagedUserSyncService::kChromeOsAvatar
, &chromeos_avatar
);
81 return CreateLocalSyncData(it
.key(), name
, acknowledged
, master_key
,
82 chrome_avatar
, chromeos_avatar
);
87 const char ManagedUserSyncService::kAcknowledged
[] = "acknowledged";
88 const char ManagedUserSyncService::kChromeAvatar
[] = "chromeAvatar";
89 const char ManagedUserSyncService::kChromeOsAvatar
[] = "chromeOsAvatar";
90 const char ManagedUserSyncService::kMasterKey
[] = "masterKey";
91 const char ManagedUserSyncService::kName
[] = "name";
92 const int ManagedUserSyncService::kNoAvatar
= -100;
94 ManagedUserSyncService::ManagedUserSyncService(PrefService
* prefs
)
96 pref_change_registrar_
.Init(prefs_
);
97 pref_change_registrar_
.Add(
98 prefs::kGoogleServicesLastUsername
,
99 base::Bind(&ManagedUserSyncService::OnLastSignedInUsernameChange
,
100 base::Unretained(this)));
103 ManagedUserSyncService::~ManagedUserSyncService() {
107 void ManagedUserSyncService::RegisterProfilePrefs(
108 PrefRegistrySyncable
* registry
) {
109 registry
->RegisterDictionaryPref(prefs::kManagedUsers
,
110 PrefRegistrySyncable::UNSYNCABLE_PREF
);
114 bool ManagedUserSyncService::GetAvatarIndex(const std::string
& avatar_str
,
116 DCHECK(avatar_index
);
117 if (avatar_str
.empty()) {
118 *avatar_index
= kNoAvatar
;
121 #if defined(OS_CHROMEOS)
122 const char* prefix
= kChromeOSAvatarPrefix
;
124 const char* prefix
= kChromeAvatarPrefix
;
126 size_t prefix_len
= strlen(prefix
);
127 if (avatar_str
.size() <= prefix_len
||
128 avatar_str
.substr(0, prefix_len
) != prefix
) {
132 return base::StringToInt(avatar_str
.substr(prefix_len
), avatar_index
);
136 std::string
ManagedUserSyncService::BuildAvatarString(int avatar_index
) {
137 #if defined(OS_CHROMEOS)
138 const char* prefix
= kChromeOSAvatarPrefix
;
140 const char* prefix
= kChromeAvatarPrefix
;
142 return base::StringPrintf("%s%d", prefix
, avatar_index
);
145 void ManagedUserSyncService::AddObserver(
146 ManagedUserSyncServiceObserver
* observer
) {
147 observers_
.AddObserver(observer
);
150 void ManagedUserSyncService::RemoveObserver(
151 ManagedUserSyncServiceObserver
* observer
) {
152 observers_
.RemoveObserver(observer
);
155 void ManagedUserSyncService::AddManagedUser(const std::string
& id
,
156 const std::string
& name
,
157 const std::string
& master_key
,
159 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
160 base::DictionaryValue
* dict
= update
.Get();
161 base::DictionaryValue
* value
= new base::DictionaryValue
;
162 value
->SetString(kName
, name
);
163 value
->SetString(kMasterKey
, master_key
);
164 std::string chrome_avatar
;
165 std::string chromeos_avatar
;
166 #if defined(OS_CHROMEOS)
167 chromeos_avatar
= BuildAvatarString(avatar_index
);
169 chrome_avatar
= BuildAvatarString(avatar_index
);
171 value
->SetString(kChromeAvatar
, chrome_avatar
);
172 value
->SetString(kChromeOsAvatar
, chromeos_avatar
);
173 DCHECK(!dict
->HasKey(id
));
174 dict
->SetWithoutPathExpansion(id
, value
);
176 if (!sync_processor_
)
179 // If we're already syncing, create a new change and upload it.
180 SyncChangeList change_list
;
181 change_list
.push_back(SyncChange(
183 SyncChange::ACTION_ADD
,
184 CreateLocalSyncData(id
, name
, false, master_key
,
185 chrome_avatar
, chromeos_avatar
)));
187 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
188 DCHECK(!error
.IsSet()) << error
.ToString();
191 void ManagedUserSyncService::DeleteManagedUser(const std::string
& id
) {
192 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
193 bool success
= update
->RemoveWithoutPathExpansion(id
, NULL
);
196 if (!sync_processor_
)
199 SyncChangeList change_list
;
200 change_list
.push_back(SyncChange(
202 SyncChange::ACTION_DELETE
,
203 SyncData::CreateLocalDelete(id
, MANAGED_USERS
)));
204 SyncError sync_error
=
205 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
206 DCHECK(!sync_error
.IsSet());
209 const base::DictionaryValue
* ManagedUserSyncService::GetManagedUsers() {
210 DCHECK(sync_processor_
);
211 return prefs_
->GetDictionary(prefs::kManagedUsers
);
214 bool ManagedUserSyncService::UpdateManagedUserAvatarIfNeeded(
215 const std::string
& id
,
217 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
218 base::DictionaryValue
* dict
= update
.Get();
219 DCHECK(dict
->HasKey(id
));
220 base::DictionaryValue
* value
= NULL
;
221 bool success
= dict
->GetDictionaryWithoutPathExpansion(id
, &value
);
224 bool acknowledged
= false;
225 value
->GetBoolean(ManagedUserSyncService::kAcknowledged
, &acknowledged
);
227 value
->GetString(ManagedUserSyncService::kName
, &name
);
228 std::string master_key
;
229 value
->GetString(ManagedUserSyncService::kMasterKey
, &master_key
);
230 std::string chromeos_avatar
;
231 value
->GetString(ManagedUserSyncService::kChromeOsAvatar
, &chromeos_avatar
);
232 std::string chrome_avatar
;
233 value
->GetString(ManagedUserSyncService::kChromeAvatar
, &chrome_avatar
);
234 // The following check is just for safety. We want to avoid that the existing
235 // avatar selection is overwritten. Currently we don't allow the user to
236 // choose a different avatar in the recreation dialog, anyway, if there is
237 // already an avatar selected.
238 #if defined(OS_CHROMEOS)
239 if (!chromeos_avatar
.empty() && avatar_index
!= kNoAvatar
)
242 if (!chrome_avatar
.empty() && avatar_index
!= kNoAvatar
)
246 chrome_avatar
= avatar_index
== kNoAvatar
?
247 std::string() : BuildAvatarString(avatar_index
);
248 #if defined(OS_CHROMEOS)
249 value
->SetString(kChromeOsAvatar
, chrome_avatar
);
251 value
->SetString(kChromeAvatar
, chrome_avatar
);
254 if (!sync_processor_
)
257 SyncChangeList change_list
;
258 change_list
.push_back(SyncChange(
260 SyncChange::ACTION_UPDATE
,
261 CreateLocalSyncData(id
, name
, acknowledged
, master_key
,
262 chrome_avatar
, chromeos_avatar
)));
264 sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
);
265 DCHECK(!error
.IsSet()) << error
.ToString();
269 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string
& id
) {
270 bool cleared
= UpdateManagedUserAvatarIfNeeded(id
, kNoAvatar
);
274 void ManagedUserSyncService::GetManagedUsersAsync(
275 const ManagedUsersCallback
& callback
) {
276 // If we are already syncing, just run the callback.
277 if (sync_processor_
) {
278 callback
.Run(GetManagedUsers());
282 // Otherwise queue it up until we start syncing.
283 callbacks_
.push_back(callback
);
286 void ManagedUserSyncService::Shutdown() {
287 NotifyManagedUsersSyncingStopped();
290 SyncMergeResult
ManagedUserSyncService::MergeDataAndStartSyncing(
292 const SyncDataList
& initial_sync_data
,
293 scoped_ptr
<SyncChangeProcessor
> sync_processor
,
294 scoped_ptr
<SyncErrorFactory
> error_handler
) {
295 DCHECK_EQ(MANAGED_USERS
, type
);
296 sync_processor_
= sync_processor
.Pass();
297 error_handler_
= error_handler
.Pass();
299 SyncChangeList change_list
;
300 SyncMergeResult
result(MANAGED_USERS
);
302 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
303 base::DictionaryValue
* dict
= update
.Get();
304 result
.set_num_items_before_association(dict
->size());
305 std::set
<std::string
> seen_ids
;
306 int num_items_added
= 0;
307 int num_items_modified
= 0;
308 for (SyncDataList::const_iterator it
= initial_sync_data
.begin();
309 it
!= initial_sync_data
.end(); ++it
) {
310 DCHECK_EQ(MANAGED_USERS
, it
->GetDataType());
311 const ManagedUserSpecifics
& managed_user
=
312 it
->GetSpecifics().managed_user();
313 base::DictionaryValue
* value
= new base::DictionaryValue();
314 value
->SetString(kName
, managed_user
.name());
315 value
->SetBoolean(kAcknowledged
, managed_user
.acknowledged());
316 value
->SetString(kMasterKey
, managed_user
.master_key());
317 value
->SetString(kChromeAvatar
, managed_user
.chrome_avatar());
318 value
->SetString(kChromeOsAvatar
, managed_user
.chromeos_avatar());
319 if (dict
->HasKey(managed_user
.id()))
320 num_items_modified
++;
323 dict
->SetWithoutPathExpansion(managed_user
.id(), value
);
324 seen_ids
.insert(managed_user
.id());
327 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd(); it
.Advance()) {
328 if (seen_ids
.find(it
.key()) != seen_ids
.end())
331 change_list
.push_back(SyncChange(FROM_HERE
, SyncChange::ACTION_ADD
,
332 CreateSyncDataFromDictionaryEntry(it
)));
334 result
.set_error(sync_processor_
->ProcessSyncChanges(FROM_HERE
, change_list
));
336 result
.set_num_items_modified(num_items_modified
);
337 result
.set_num_items_added(num_items_added
);
338 result
.set_num_items_after_association(dict
->size());
345 void ManagedUserSyncService::StopSyncing(ModelType type
) {
346 DCHECK_EQ(MANAGED_USERS
, type
);
347 // The observers may want to change the Sync data, so notify them before
348 // resetting the |sync_processor_|.
349 NotifyManagedUsersSyncingStopped();
350 sync_processor_
.reset();
351 error_handler_
.reset();
354 SyncDataList
ManagedUserSyncService::GetAllSyncData(
355 ModelType type
) const {
357 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
358 base::DictionaryValue
* dict
= update
.Get();
359 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd(); it
.Advance())
360 data
.push_back(CreateSyncDataFromDictionaryEntry(it
));
365 SyncError
ManagedUserSyncService::ProcessSyncChanges(
366 const tracked_objects::Location
& from_here
,
367 const SyncChangeList
& change_list
) {
369 DictionaryPrefUpdate
update(prefs_
, prefs::kManagedUsers
);
370 base::DictionaryValue
* dict
= update
.Get();
371 for (SyncChangeList::const_iterator it
= change_list
.begin();
372 it
!= change_list
.end(); ++it
) {
373 SyncData data
= it
->sync_data();
374 DCHECK_EQ(MANAGED_USERS
, data
.GetDataType());
375 const ManagedUserSpecifics
& managed_user
=
376 data
.GetSpecifics().managed_user();
377 switch (it
->change_type()) {
378 case SyncChange::ACTION_ADD
:
379 case SyncChange::ACTION_UPDATE
: {
380 // Every item we get from the server should be acknowledged.
381 DCHECK(managed_user
.acknowledged());
382 const base::DictionaryValue
* old_value
= NULL
;
383 dict
->GetDictionaryWithoutPathExpansion(managed_user
.id(), &old_value
);
385 // For an update action, the managed user should already exist, for an
386 // add action, it should not.
388 old_value
? SyncChange::ACTION_UPDATE
: SyncChange::ACTION_ADD
,
391 // If the managed user switched from unacknowledged to acknowledged,
392 // we might need to continue with a registration.
393 if (old_value
&& !old_value
->HasKey(kAcknowledged
))
394 NotifyManagedUserAcknowledged(managed_user
.id());
396 base::DictionaryValue
* value
= new base::DictionaryValue
;
397 value
->SetString(kName
, managed_user
.name());
398 value
->SetBoolean(kAcknowledged
, managed_user
.acknowledged());
399 value
->SetString(kMasterKey
, managed_user
.master_key());
400 value
->SetString(kChromeAvatar
, managed_user
.chrome_avatar());
401 value
->SetString(kChromeOsAvatar
, managed_user
.chromeos_avatar());
402 dict
->SetWithoutPathExpansion(managed_user
.id(), value
);
405 case SyncChange::ACTION_DELETE
: {
406 DCHECK(dict
->HasKey(managed_user
.id())) << managed_user
.id();
407 dict
->RemoveWithoutPathExpansion(managed_user
.id(), NULL
);
410 case SyncChange::ACTION_INVALID
: {
419 void ManagedUserSyncService::OnLastSignedInUsernameChange() {
420 DCHECK(!sync_processor_
);
422 // If the last signed in user changes, we clear all data, to avoid managed
423 // users from one custodian appearing in another one's profile.
424 prefs_
->ClearPref(prefs::kManagedUsers
);
427 void ManagedUserSyncService::NotifyManagedUserAcknowledged(
428 const std::string
& managed_user_id
) {
429 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver
, observers_
,
430 OnManagedUserAcknowledged(managed_user_id
));
433 void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() {
434 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver
, observers_
,
435 OnManagedUsersSyncingStopped());
438 void ManagedUserSyncService::DispatchCallbacks() {
439 const base::DictionaryValue
* managed_users
=
440 prefs_
->GetDictionary(prefs::kManagedUsers
);
441 for (std::vector
<ManagedUsersCallback
>::iterator it
= callbacks_
.begin();
442 it
!= callbacks_
.end(); ++it
) {
443 it
->Run(managed_users
);