Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / supervised_user / legacy / supervised_user_sync_service.cc
blob1bcfb85bc219fcfb53d313a050b9d6ff4d8e2eea
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/legacy/supervised_user_sync_service.h"
7 #include <set>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "components/signin/core/browser/signin_manager.h"
21 #include "sync/api/sync_change.h"
22 #include "sync/api/sync_data.h"
23 #include "sync/api/sync_error.h"
24 #include "sync/api/sync_error_factory.h"
25 #include "sync/api/sync_merge_result.h"
26 #include "sync/protocol/sync.pb.h"
28 #if defined(OS_CHROMEOS)
29 #include "components/user_manager/user_image/default_user_images.h"
30 #endif
32 using base::DictionaryValue;
33 using user_prefs::PrefRegistrySyncable;
34 using syncer::SUPERVISED_USERS;
35 using syncer::ModelType;
36 using syncer::SyncChange;
37 using syncer::SyncChangeList;
38 using syncer::SyncChangeProcessor;
39 using syncer::SyncData;
40 using syncer::SyncDataList;
41 using syncer::SyncError;
42 using syncer::SyncErrorFactory;
43 using syncer::SyncMergeResult;
44 using sync_pb::ManagedUserSpecifics;
46 namespace {
48 #if defined(OS_CHROMEOS)
49 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
50 #else
51 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
52 #endif
54 SyncData CreateLocalSyncData(const std::string& id,
55 const std::string& name,
56 bool acknowledged,
57 const std::string& master_key,
58 const std::string& chrome_avatar,
59 const std::string& chromeos_avatar,
60 const std::string& password_signature_key,
61 const std::string& password_encryption_key) {
62 ::sync_pb::EntitySpecifics specifics;
63 specifics.mutable_managed_user()->set_id(id);
64 specifics.mutable_managed_user()->set_name(name);
65 if (!chrome_avatar.empty())
66 specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
67 if (!chromeos_avatar.empty())
68 specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
69 if (!master_key.empty())
70 specifics.mutable_managed_user()->set_master_key(master_key);
71 if (acknowledged)
72 specifics.mutable_managed_user()->set_acknowledged(true);
73 if (!password_signature_key.empty()) {
74 specifics.mutable_managed_user()->
75 set_password_signature_key(password_signature_key);
77 if (!password_encryption_key.empty()) {
78 specifics.mutable_managed_user()->
79 set_password_encryption_key(password_encryption_key);
81 return SyncData::CreateLocalData(id, name, specifics);
84 SyncData CreateSyncDataFromDictionaryEntry(const std::string& id,
85 const base::Value& value) {
86 const base::DictionaryValue* dict = NULL;
87 bool success = value.GetAsDictionary(&dict);
88 DCHECK(success);
89 bool acknowledged = false;
90 dict->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
91 std::string name;
92 dict->GetString(SupervisedUserSyncService::kName, &name);
93 DCHECK(!name.empty());
94 std::string master_key;
95 dict->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
96 std::string chrome_avatar;
97 dict->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
98 std::string chromeos_avatar;
99 dict->GetString(SupervisedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
100 std::string signature;
101 dict->GetString(SupervisedUserSyncService::kPasswordSignatureKey, &signature);
102 std::string encryption;
103 dict->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
104 &encryption);
106 return CreateLocalSyncData(id,
107 name,
108 acknowledged,
109 master_key,
110 chrome_avatar,
111 chromeos_avatar,
112 signature,
113 encryption);
116 } // namespace
118 const char SupervisedUserSyncService::kAcknowledged[] = "acknowledged";
119 const char SupervisedUserSyncService::kChromeAvatar[] = "chromeAvatar";
120 const char SupervisedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
121 const char SupervisedUserSyncService::kMasterKey[] = "masterKey";
122 const char SupervisedUserSyncService::kName[] = "name";
123 const char SupervisedUserSyncService::kPasswordSignatureKey[] =
124 "passwordSignatureKey";
125 const char SupervisedUserSyncService::kPasswordEncryptionKey[] =
126 "passwordEncryptionKey";
127 const int SupervisedUserSyncService::kNoAvatar = -100;
129 SupervisedUserSyncService::SupervisedUserSyncService(Profile* profile)
130 : profile_(profile), prefs_(profile->GetPrefs()) {
131 SigninManagerFactory::GetForProfile(profile_)->AddObserver(this);
134 SupervisedUserSyncService::~SupervisedUserSyncService() {
137 // static
138 void SupervisedUserSyncService::RegisterProfilePrefs(
139 PrefRegistrySyncable* registry) {
140 registry->RegisterDictionaryPref(prefs::kSupervisedUsers,
141 PrefRegistrySyncable::UNSYNCABLE_PREF);
144 // static
145 bool SupervisedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
146 int* avatar_index) {
147 DCHECK(avatar_index);
148 if (avatar_str.empty()) {
149 *avatar_index = kNoAvatar;
150 return true;
152 #if defined(OS_CHROMEOS)
153 const char* prefix = kChromeOSAvatarPrefix;
154 #else
155 const char* prefix = kChromeAvatarPrefix;
156 #endif
157 size_t prefix_len = strlen(prefix);
158 if (avatar_str.size() <= prefix_len ||
159 avatar_str.substr(0, prefix_len) != prefix) {
160 return false;
163 if (!base::StringToInt(avatar_str.substr(prefix_len), avatar_index))
164 return false;
166 const int kChromeOSDummyAvatarIndex = -111;
168 #if defined(OS_CHROMEOS)
169 return (*avatar_index == kChromeOSDummyAvatarIndex ||
170 (*avatar_index >= user_manager::kFirstDefaultImageIndex &&
171 *avatar_index < user_manager::kDefaultImagesCount));
172 #else
173 // Check if the Chrome avatar index is set to a dummy value. Some early
174 // supervised user profiles on ChromeOS stored a dummy avatar index as a
175 // Chrome Avatar before there was logic to sync the ChromeOS avatar
176 // separately. Handle this as if the Chrome Avatar was not chosen yet (which
177 // is correct for these profiles).
178 if (*avatar_index == kChromeOSDummyAvatarIndex)
179 *avatar_index = kNoAvatar;
180 return (*avatar_index == kNoAvatar ||
181 (*avatar_index >= 0 &&
182 static_cast<size_t>(*avatar_index) <
183 profiles::GetDefaultAvatarIconCount()));
184 #endif
187 // static
188 std::string SupervisedUserSyncService::BuildAvatarString(int avatar_index) {
189 #if defined(OS_CHROMEOS)
190 const char* prefix = kChromeOSAvatarPrefix;
191 #else
192 const char* prefix = kChromeAvatarPrefix;
193 #endif
194 return base::StringPrintf("%s%d", prefix, avatar_index);
197 void SupervisedUserSyncService::AddObserver(
198 SupervisedUserSyncServiceObserver* observer) {
199 observers_.AddObserver(observer);
202 void SupervisedUserSyncService::RemoveObserver(
203 SupervisedUserSyncServiceObserver* observer) {
204 observers_.RemoveObserver(observer);
207 scoped_ptr<base::DictionaryValue> SupervisedUserSyncService::CreateDictionary(
208 const std::string& name,
209 const std::string& master_key,
210 const std::string& signature_key,
211 const std::string& encryption_key,
212 int avatar_index) {
213 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
214 result->SetString(kName, name);
215 result->SetString(kMasterKey, master_key);
216 result->SetString(kPasswordSignatureKey, signature_key);
217 result->SetString(kPasswordEncryptionKey, encryption_key);
218 // TODO(akuegel): Get rid of the avatar stuff here when Chrome OS switches
219 // to the avatar index that is stored as a shared setting.
220 std::string chrome_avatar;
221 std::string chromeos_avatar;
222 #if defined(OS_CHROMEOS)
223 chromeos_avatar = BuildAvatarString(avatar_index);
224 #else
225 chrome_avatar = BuildAvatarString(avatar_index);
226 #endif
227 result->SetString(kChromeAvatar, chrome_avatar);
228 result->SetString(kChromeOsAvatar, chromeos_avatar);
229 return result.Pass();
232 void SupervisedUserSyncService::AddSupervisedUser(
233 const std::string& id,
234 const std::string& name,
235 const std::string& master_key,
236 const std::string& signature_key,
237 const std::string& encryption_key,
238 int avatar_index) {
239 UpdateSupervisedUserImpl(id,
240 name,
241 master_key,
242 signature_key,
243 encryption_key,
244 avatar_index,
245 true /* add */);
248 void SupervisedUserSyncService::UpdateSupervisedUser(
249 const std::string& id,
250 const std::string& name,
251 const std::string& master_key,
252 const std::string& signature_key,
253 const std::string& encryption_key,
254 int avatar_index) {
255 UpdateSupervisedUserImpl(id,
256 name,
257 master_key,
258 signature_key,
259 encryption_key,
260 avatar_index,
261 false /* update */);
264 void SupervisedUserSyncService::UpdateSupervisedUserImpl(
265 const std::string& id,
266 const std::string& name,
267 const std::string& master_key,
268 const std::string& signature_key,
269 const std::string& encryption_key,
270 int avatar_index,
271 bool add_user) {
272 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
273 base::DictionaryValue* dict = update.Get();
274 scoped_ptr<base::DictionaryValue> value = CreateDictionary(
275 name, master_key, signature_key, encryption_key, avatar_index);
277 DCHECK_EQ(add_user, !dict->HasKey(id));
278 base::DictionaryValue* entry = value.get();
279 dict->SetWithoutPathExpansion(id, value.release());
281 if (!sync_processor_)
282 return;
284 // If we're already syncing, create a new change and upload it.
285 SyncChangeList change_list;
286 change_list.push_back(
287 SyncChange(FROM_HERE,
288 add_user ? SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE,
289 CreateSyncDataFromDictionaryEntry(id, *entry)));
290 SyncError error =
291 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
292 DCHECK(!error.IsSet()) << error.ToString();
295 void SupervisedUserSyncService::DeleteSupervisedUser(const std::string& id) {
296 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
297 bool success = update->RemoveWithoutPathExpansion(id, NULL);
298 DCHECK(success);
300 if (!sync_processor_)
301 return;
303 SyncChangeList change_list;
304 change_list.push_back(SyncChange(
305 FROM_HERE,
306 SyncChange::ACTION_DELETE,
307 SyncData::CreateLocalDelete(id, SUPERVISED_USERS)));
308 SyncError sync_error =
309 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
310 DCHECK(!sync_error.IsSet());
313 const base::DictionaryValue* SupervisedUserSyncService::GetSupervisedUsers() {
314 DCHECK(sync_processor_);
315 return prefs_->GetDictionary(prefs::kSupervisedUsers);
318 bool SupervisedUserSyncService::UpdateSupervisedUserAvatarIfNeeded(
319 const std::string& id,
320 int avatar_index) {
321 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
322 base::DictionaryValue* dict = update.Get();
323 DCHECK(dict->HasKey(id));
324 base::DictionaryValue* value = NULL;
325 bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
326 DCHECK(success);
328 bool acknowledged = false;
329 value->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
330 std::string name;
331 value->GetString(SupervisedUserSyncService::kName, &name);
332 std::string master_key;
333 value->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
334 std::string signature;
335 value->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
336 &signature);
337 std::string encryption;
338 value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
339 &encryption);
340 std::string chromeos_avatar;
341 value->GetString(SupervisedUserSyncService::kChromeOsAvatar,
342 &chromeos_avatar);
343 std::string chrome_avatar;
344 value->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
345 // The following check is just for safety. We want to avoid that the existing
346 // avatar selection is overwritten. Currently we don't allow the user to
347 // choose a different avatar in the recreation dialog, anyway, if there is
348 // already an avatar selected.
349 #if defined(OS_CHROMEOS)
350 if (!chromeos_avatar.empty() && avatar_index != kNoAvatar)
351 return false;
352 #else
353 if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
354 return false;
355 #endif
357 chrome_avatar = avatar_index == kNoAvatar ?
358 std::string() : BuildAvatarString(avatar_index);
359 #if defined(OS_CHROMEOS)
360 value->SetString(kChromeOsAvatar, chrome_avatar);
361 #else
362 value->SetString(kChromeAvatar, chrome_avatar);
363 #endif
365 if (!sync_processor_)
366 return true;
368 SyncChangeList change_list;
369 change_list.push_back(SyncChange(
370 FROM_HERE,
371 SyncChange::ACTION_UPDATE,
372 CreateLocalSyncData(id, name, acknowledged, master_key,
373 chrome_avatar, chromeos_avatar,
374 signature, encryption)));
375 SyncError error =
376 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
377 DCHECK(!error.IsSet()) << error.ToString();
378 return true;
381 void SupervisedUserSyncService::ClearSupervisedUserAvatar(
382 const std::string& id) {
383 bool cleared = UpdateSupervisedUserAvatarIfNeeded(id, kNoAvatar);
384 DCHECK(cleared);
387 void SupervisedUserSyncService::GetSupervisedUsersAsync(
388 const SupervisedUsersCallback& callback) {
389 // If we are already syncing, just run the callback.
390 if (sync_processor_) {
391 callback.Run(GetSupervisedUsers());
392 return;
395 // Otherwise queue it up until we start syncing.
396 callbacks_.push_back(callback);
399 void SupervisedUserSyncService::Shutdown() {
400 NotifySupervisedUsersSyncingStopped();
401 SigninManagerFactory::GetForProfile(profile_)->RemoveObserver(this);
404 SyncMergeResult SupervisedUserSyncService::MergeDataAndStartSyncing(
405 ModelType type,
406 const SyncDataList& initial_sync_data,
407 scoped_ptr<SyncChangeProcessor> sync_processor,
408 scoped_ptr<SyncErrorFactory> error_handler) {
409 DCHECK_EQ(SUPERVISED_USERS, type);
410 sync_processor_ = sync_processor.Pass();
411 error_handler_ = error_handler.Pass();
413 SyncChangeList change_list;
414 SyncMergeResult result(SUPERVISED_USERS);
416 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
417 base::DictionaryValue* dict = update.Get();
418 result.set_num_items_before_association(dict->size());
419 std::set<std::string> seen_ids;
420 int num_items_added = 0;
421 int num_items_modified = 0;
422 for (const SyncData& sync_data : initial_sync_data) {
423 DCHECK_EQ(SUPERVISED_USERS, sync_data.GetDataType());
424 const ManagedUserSpecifics& supervised_user =
425 sync_data.GetSpecifics().managed_user();
426 base::DictionaryValue* value = new base::DictionaryValue();
427 value->SetString(kName, supervised_user.name());
428 value->SetBoolean(kAcknowledged, supervised_user.acknowledged());
429 value->SetString(kMasterKey, supervised_user.master_key());
430 value->SetString(kChromeAvatar, supervised_user.chrome_avatar());
431 value->SetString(kChromeOsAvatar, supervised_user.chromeos_avatar());
432 value->SetString(kPasswordSignatureKey,
433 supervised_user.password_signature_key());
434 value->SetString(kPasswordEncryptionKey,
435 supervised_user.password_encryption_key());
436 if (dict->HasKey(supervised_user.id()))
437 num_items_modified++;
438 else
439 num_items_added++;
440 dict->SetWithoutPathExpansion(supervised_user.id(), value);
441 seen_ids.insert(supervised_user.id());
444 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
445 if (seen_ids.find(it.key()) != seen_ids.end())
446 continue;
448 change_list.push_back(
449 SyncChange(FROM_HERE,
450 SyncChange::ACTION_ADD,
451 CreateSyncDataFromDictionaryEntry(it.key(), it.value())));
453 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
455 result.set_num_items_modified(num_items_modified);
456 result.set_num_items_added(num_items_added);
457 result.set_num_items_after_association(dict->size());
459 DispatchCallbacks();
461 return result;
464 void SupervisedUserSyncService::StopSyncing(ModelType type) {
465 DCHECK_EQ(SUPERVISED_USERS, type);
466 // The observers may want to change the Sync data, so notify them before
467 // resetting the |sync_processor_|.
468 NotifySupervisedUsersSyncingStopped();
469 sync_processor_.reset();
470 error_handler_.reset();
473 SyncDataList SupervisedUserSyncService::GetAllSyncData(
474 ModelType type) const {
475 SyncDataList data;
476 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
477 base::DictionaryValue* dict = update.Get();
478 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
479 data.push_back(CreateSyncDataFromDictionaryEntry(it.key(), it.value()));
481 return data;
484 SyncError SupervisedUserSyncService::ProcessSyncChanges(
485 const tracked_objects::Location& from_here,
486 const SyncChangeList& change_list) {
487 SyncError error;
488 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
489 base::DictionaryValue* dict = update.Get();
490 for (const SyncChange& sync_change : change_list) {
491 SyncData data = sync_change.sync_data();
492 DCHECK_EQ(SUPERVISED_USERS, data.GetDataType());
493 const ManagedUserSpecifics& supervised_user =
494 data.GetSpecifics().managed_user();
495 switch (sync_change.change_type()) {
496 case SyncChange::ACTION_ADD:
497 case SyncChange::ACTION_UPDATE: {
498 // Every item we get from the server should be acknowledged.
499 DCHECK(supervised_user.acknowledged());
500 const base::DictionaryValue* old_value = NULL;
501 dict->GetDictionaryWithoutPathExpansion(supervised_user.id(),
502 &old_value);
504 // For an update action, the supervised user should already exist, for
505 // an add action, it should not.
506 DCHECK_EQ(
507 old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
508 sync_change.change_type());
510 // If the supervised user switched from unacknowledged to acknowledged,
511 // we might need to continue with a registration.
512 if (old_value && !old_value->HasKey(kAcknowledged))
513 NotifySupervisedUserAcknowledged(supervised_user.id());
515 base::DictionaryValue* value = new base::DictionaryValue;
516 value->SetString(kName, supervised_user.name());
517 value->SetBoolean(kAcknowledged, supervised_user.acknowledged());
518 value->SetString(kMasterKey, supervised_user.master_key());
519 value->SetString(kChromeAvatar, supervised_user.chrome_avatar());
520 value->SetString(kChromeOsAvatar, supervised_user.chromeos_avatar());
521 value->SetString(kPasswordSignatureKey,
522 supervised_user.password_signature_key());
523 value->SetString(kPasswordEncryptionKey,
524 supervised_user.password_encryption_key());
525 dict->SetWithoutPathExpansion(supervised_user.id(), value);
527 NotifySupervisedUsersChanged();
528 break;
530 case SyncChange::ACTION_DELETE: {
531 DCHECK(dict->HasKey(supervised_user.id())) << supervised_user.id();
532 dict->RemoveWithoutPathExpansion(supervised_user.id(), NULL);
533 break;
535 case SyncChange::ACTION_INVALID: {
536 NOTREACHED();
537 break;
541 return error;
544 void SupervisedUserSyncService::GoogleSignedOut(
545 const std::string& account_id,
546 const std::string& username) {
547 DCHECK(!sync_processor_);
549 // Clear all data on signout, to avoid supervised users from one custodian
550 // appearing in another one's profile.
551 prefs_->ClearPref(prefs::kSupervisedUsers);
554 void SupervisedUserSyncService::NotifySupervisedUserAcknowledged(
555 const std::string& supervised_user_id) {
556 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
557 OnSupervisedUserAcknowledged(supervised_user_id));
560 void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() {
561 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
562 OnSupervisedUsersSyncingStopped());
565 void SupervisedUserSyncService::NotifySupervisedUsersChanged() {
566 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver,
567 observers_,
568 OnSupervisedUsersChanged());
571 void SupervisedUserSyncService::DispatchCallbacks() {
572 const base::DictionaryValue* supervised_users =
573 prefs_->GetDictionary(prefs::kSupervisedUsers);
574 for (const auto& callback : callbacks_)
575 callback.Run(supervised_users);
576 callbacks_.clear();