Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / managed_mode / managed_user_sync_service.cc
blobc9fcbb0361b3cf98d2f91085aca73a3e30a11dd4
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"
7 #include "base/bind.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;
36 namespace {
38 #if defined(OS_CHROMEOS)
39 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
40 #else
41 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
42 #endif
44 SyncData CreateLocalSyncData(const std::string& id,
45 const std::string& name,
46 bool acknowledged,
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);
59 if (acknowledged)
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);
68 DCHECK(success);
69 bool acknowledged = false;
70 dict->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
71 std::string name;
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);
85 } // namespace
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)
95 : prefs_(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() {
106 // static
107 void ManagedUserSyncService::RegisterProfilePrefs(
108 PrefRegistrySyncable* registry) {
109 registry->RegisterDictionaryPref(prefs::kManagedUsers,
110 PrefRegistrySyncable::UNSYNCABLE_PREF);
113 // static
114 bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
115 int* avatar_index) {
116 DCHECK(avatar_index);
117 if (avatar_str.empty()) {
118 *avatar_index = kNoAvatar;
119 return true;
121 #if defined(OS_CHROMEOS)
122 const char* prefix = kChromeOSAvatarPrefix;
123 #else
124 const char* prefix = kChromeAvatarPrefix;
125 #endif
126 size_t prefix_len = strlen(prefix);
127 if (avatar_str.size() <= prefix_len ||
128 avatar_str.substr(0, prefix_len) != prefix) {
129 return false;
132 return base::StringToInt(avatar_str.substr(prefix_len), avatar_index);
135 // static
136 std::string ManagedUserSyncService::BuildAvatarString(int avatar_index) {
137 #if defined(OS_CHROMEOS)
138 const char* prefix = kChromeOSAvatarPrefix;
139 #else
140 const char* prefix = kChromeAvatarPrefix;
141 #endif
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,
158 int avatar_index) {
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);
168 #else
169 chrome_avatar = BuildAvatarString(avatar_index);
170 #endif
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_)
177 return;
179 // If we're already syncing, create a new change and upload it.
180 SyncChangeList change_list;
181 change_list.push_back(SyncChange(
182 FROM_HERE,
183 SyncChange::ACTION_ADD,
184 CreateLocalSyncData(id, name, false, master_key,
185 chrome_avatar, chromeos_avatar)));
186 SyncError error =
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);
194 DCHECK(success);
196 if (!sync_processor_)
197 return;
199 SyncChangeList change_list;
200 change_list.push_back(SyncChange(
201 FROM_HERE,
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,
216 int avatar_index) {
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);
222 DCHECK(success);
224 bool acknowledged = false;
225 value->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
226 std::string name;
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)
240 return false;
241 #else
242 if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
243 return false;
244 #endif
246 chrome_avatar = avatar_index == kNoAvatar ?
247 std::string() : BuildAvatarString(avatar_index);
248 #if defined(OS_CHROMEOS)
249 value->SetString(kChromeOsAvatar, chrome_avatar);
250 #else
251 value->SetString(kChromeAvatar, chrome_avatar);
252 #endif
254 if (!sync_processor_)
255 return true;
257 SyncChangeList change_list;
258 change_list.push_back(SyncChange(
259 FROM_HERE,
260 SyncChange::ACTION_UPDATE,
261 CreateLocalSyncData(id, name, acknowledged, master_key,
262 chrome_avatar, chromeos_avatar)));
263 SyncError error =
264 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
265 DCHECK(!error.IsSet()) << error.ToString();
266 return true;
269 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string& id) {
270 bool cleared = UpdateManagedUserAvatarIfNeeded(id, kNoAvatar);
271 DCHECK(cleared);
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());
279 return;
282 // Otherwise queue it up until we start syncing.
283 callbacks_.push_back(callback);
286 void ManagedUserSyncService::Shutdown() {
287 NotifyManagedUsersSyncingStopped();
290 SyncMergeResult ManagedUserSyncService::MergeDataAndStartSyncing(
291 ModelType type,
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++;
321 else
322 num_items_added++;
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())
329 continue;
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());
340 DispatchCallbacks();
342 return result;
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 {
356 SyncDataList data;
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));
362 return data;
365 SyncError ManagedUserSyncService::ProcessSyncChanges(
366 const tracked_objects::Location& from_here,
367 const SyncChangeList& change_list) {
368 SyncError error;
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.
387 DCHECK_EQ(
388 old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
389 it->change_type());
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);
403 break;
405 case SyncChange::ACTION_DELETE: {
406 DCHECK(dict->HasKey(managed_user.id())) << managed_user.id();
407 dict->RemoveWithoutPathExpansion(managed_user.id(), NULL);
408 break;
410 case SyncChange::ACTION_INVALID: {
411 NOTREACHED();
412 break;
416 return error;
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);
445 callbacks_.clear();