Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_sync_service.cc
blob13caa52a257de70c9f48cc49d1cdfb2c14cdcab6
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_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/browser/profiles/profile_avatar_icon_util.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/pref_registry/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 #if defined(OS_CHROMEOS)
24 #include "components/user_manager/user_image/default_user_images.h"
25 #endif
27 using base::DictionaryValue;
28 using user_prefs::PrefRegistrySyncable;
29 using syncer::SUPERVISED_USERS;
30 using syncer::ModelType;
31 using syncer::SyncChange;
32 using syncer::SyncChangeList;
33 using syncer::SyncChangeProcessor;
34 using syncer::SyncData;
35 using syncer::SyncDataList;
36 using syncer::SyncError;
37 using syncer::SyncErrorFactory;
38 using syncer::SyncMergeResult;
39 using sync_pb::ManagedUserSpecifics;
41 namespace {
43 #if defined(OS_CHROMEOS)
44 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
45 #else
46 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
47 #endif
49 SyncData CreateLocalSyncData(const std::string& id,
50 const std::string& name,
51 bool acknowledged,
52 const std::string& master_key,
53 const std::string& chrome_avatar,
54 const std::string& chromeos_avatar,
55 const std::string& password_signature_key,
56 const std::string& password_encryption_key) {
57 ::sync_pb::EntitySpecifics specifics;
58 specifics.mutable_managed_user()->set_id(id);
59 specifics.mutable_managed_user()->set_name(name);
60 if (!chrome_avatar.empty())
61 specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
62 if (!chromeos_avatar.empty())
63 specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
64 if (!master_key.empty())
65 specifics.mutable_managed_user()->set_master_key(master_key);
66 if (acknowledged)
67 specifics.mutable_managed_user()->set_acknowledged(true);
68 if (!password_signature_key.empty()) {
69 specifics.mutable_managed_user()->
70 set_password_signature_key(password_signature_key);
72 if (!password_encryption_key.empty()) {
73 specifics.mutable_managed_user()->
74 set_password_encryption_key(password_encryption_key);
76 return SyncData::CreateLocalData(id, name, specifics);
79 SyncData CreateSyncDataFromDictionaryEntry(const std::string& id,
80 const base::Value& value) {
81 const base::DictionaryValue* dict = NULL;
82 bool success = value.GetAsDictionary(&dict);
83 DCHECK(success);
84 bool acknowledged = false;
85 dict->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
86 std::string name;
87 dict->GetString(SupervisedUserSyncService::kName, &name);
88 DCHECK(!name.empty());
89 std::string master_key;
90 dict->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
91 std::string chrome_avatar;
92 dict->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
93 std::string chromeos_avatar;
94 dict->GetString(SupervisedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
95 std::string signature;
96 dict->GetString(SupervisedUserSyncService::kPasswordSignatureKey, &signature);
97 std::string encryption;
98 dict->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
99 &encryption);
101 return CreateLocalSyncData(id,
102 name,
103 acknowledged,
104 master_key,
105 chrome_avatar,
106 chromeos_avatar,
107 signature,
108 encryption);
111 } // namespace
113 const char SupervisedUserSyncService::kAcknowledged[] = "acknowledged";
114 const char SupervisedUserSyncService::kChromeAvatar[] = "chromeAvatar";
115 const char SupervisedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
116 const char SupervisedUserSyncService::kMasterKey[] = "masterKey";
117 const char SupervisedUserSyncService::kName[] = "name";
118 const char SupervisedUserSyncService::kPasswordSignatureKey[] =
119 "passwordSignatureKey";
120 const char SupervisedUserSyncService::kPasswordEncryptionKey[] =
121 "passwordEncryptionKey";
122 const int SupervisedUserSyncService::kNoAvatar = -100;
124 SupervisedUserSyncService::SupervisedUserSyncService(PrefService* prefs)
125 : prefs_(prefs) {
126 pref_change_registrar_.Init(prefs_);
127 pref_change_registrar_.Add(
128 prefs::kGoogleServicesLastUsername,
129 base::Bind(&SupervisedUserSyncService::OnLastSignedInUsernameChange,
130 base::Unretained(this)));
133 SupervisedUserSyncService::~SupervisedUserSyncService() {
136 // static
137 void SupervisedUserSyncService::RegisterProfilePrefs(
138 PrefRegistrySyncable* registry) {
139 registry->RegisterDictionaryPref(prefs::kSupervisedUsers,
140 PrefRegistrySyncable::UNSYNCABLE_PREF);
143 // static
144 bool SupervisedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
145 int* avatar_index) {
146 DCHECK(avatar_index);
147 if (avatar_str.empty()) {
148 *avatar_index = kNoAvatar;
149 return true;
151 #if defined(OS_CHROMEOS)
152 const char* prefix = kChromeOSAvatarPrefix;
153 #else
154 const char* prefix = kChromeAvatarPrefix;
155 #endif
156 size_t prefix_len = strlen(prefix);
157 if (avatar_str.size() <= prefix_len ||
158 avatar_str.substr(0, prefix_len) != prefix) {
159 return false;
162 if (!base::StringToInt(avatar_str.substr(prefix_len), avatar_index))
163 return false;
165 const int kChromeOSDummyAvatarIndex = -111;
167 #if defined(OS_CHROMEOS)
168 return (*avatar_index == kChromeOSDummyAvatarIndex ||
169 (*avatar_index >= user_manager::kFirstDefaultImageIndex &&
170 *avatar_index < user_manager::kDefaultImagesCount));
171 #else
172 // Check if the Chrome avatar index is set to a dummy value. Some early
173 // supervised user profiles on ChromeOS stored a dummy avatar index as a
174 // Chrome Avatar before there was logic to sync the ChromeOS avatar
175 // separately. Handle this as if the Chrome Avatar was not chosen yet (which
176 // is correct for these profiles).
177 if (*avatar_index == kChromeOSDummyAvatarIndex)
178 *avatar_index = kNoAvatar;
179 return (*avatar_index == kNoAvatar ||
180 (*avatar_index >= 0 &&
181 static_cast<size_t>(*avatar_index) <
182 profiles::GetDefaultAvatarIconCount()));
183 #endif
186 // static
187 std::string SupervisedUserSyncService::BuildAvatarString(int avatar_index) {
188 #if defined(OS_CHROMEOS)
189 const char* prefix = kChromeOSAvatarPrefix;
190 #else
191 const char* prefix = kChromeAvatarPrefix;
192 #endif
193 return base::StringPrintf("%s%d", prefix, avatar_index);
196 void SupervisedUserSyncService::AddObserver(
197 SupervisedUserSyncServiceObserver* observer) {
198 observers_.AddObserver(observer);
201 void SupervisedUserSyncService::RemoveObserver(
202 SupervisedUserSyncServiceObserver* observer) {
203 observers_.RemoveObserver(observer);
206 scoped_ptr<base::DictionaryValue> SupervisedUserSyncService::CreateDictionary(
207 const std::string& name,
208 const std::string& master_key,
209 const std::string& signature_key,
210 const std::string& encryption_key,
211 int avatar_index) {
212 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
213 result->SetString(kName, name);
214 result->SetString(kMasterKey, master_key);
215 result->SetString(kPasswordSignatureKey, signature_key);
216 result->SetString(kPasswordEncryptionKey, encryption_key);
217 // TODO(akuegel): Get rid of the avatar stuff here when Chrome OS switches
218 // to the avatar index that is stored as a shared setting.
219 std::string chrome_avatar;
220 std::string chromeos_avatar;
221 #if defined(OS_CHROMEOS)
222 chromeos_avatar = BuildAvatarString(avatar_index);
223 #else
224 chrome_avatar = BuildAvatarString(avatar_index);
225 #endif
226 result->SetString(kChromeAvatar, chrome_avatar);
227 result->SetString(kChromeOsAvatar, chromeos_avatar);
228 return result.Pass();
231 void SupervisedUserSyncService::AddSupervisedUser(
232 const std::string& id,
233 const std::string& name,
234 const std::string& master_key,
235 const std::string& signature_key,
236 const std::string& encryption_key,
237 int avatar_index) {
238 UpdateSupervisedUserImpl(id,
239 name,
240 master_key,
241 signature_key,
242 encryption_key,
243 avatar_index,
244 true /* add */);
247 void SupervisedUserSyncService::UpdateSupervisedUser(
248 const std::string& id,
249 const std::string& name,
250 const std::string& master_key,
251 const std::string& signature_key,
252 const std::string& encryption_key,
253 int avatar_index) {
254 UpdateSupervisedUserImpl(id,
255 name,
256 master_key,
257 signature_key,
258 encryption_key,
259 avatar_index,
260 false /* update */);
263 void SupervisedUserSyncService::UpdateSupervisedUserImpl(
264 const std::string& id,
265 const std::string& name,
266 const std::string& master_key,
267 const std::string& signature_key,
268 const std::string& encryption_key,
269 int avatar_index,
270 bool add_user) {
271 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
272 base::DictionaryValue* dict = update.Get();
273 scoped_ptr<base::DictionaryValue> value = CreateDictionary(
274 name, master_key, signature_key, encryption_key, avatar_index);
276 DCHECK_EQ(add_user, !dict->HasKey(id));
277 base::DictionaryValue* entry = value.get();
278 dict->SetWithoutPathExpansion(id, value.release());
280 if (!sync_processor_)
281 return;
283 // If we're already syncing, create a new change and upload it.
284 SyncChangeList change_list;
285 change_list.push_back(
286 SyncChange(FROM_HERE,
287 add_user ? SyncChange::ACTION_ADD : SyncChange::ACTION_UPDATE,
288 CreateSyncDataFromDictionaryEntry(id, *entry)));
289 SyncError error =
290 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
291 DCHECK(!error.IsSet()) << error.ToString();
294 void SupervisedUserSyncService::DeleteSupervisedUser(const std::string& id) {
295 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
296 bool success = update->RemoveWithoutPathExpansion(id, NULL);
297 DCHECK(success);
299 if (!sync_processor_)
300 return;
302 SyncChangeList change_list;
303 change_list.push_back(SyncChange(
304 FROM_HERE,
305 SyncChange::ACTION_DELETE,
306 SyncData::CreateLocalDelete(id, SUPERVISED_USERS)));
307 SyncError sync_error =
308 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
309 DCHECK(!sync_error.IsSet());
312 const base::DictionaryValue* SupervisedUserSyncService::GetSupervisedUsers() {
313 DCHECK(sync_processor_);
314 return prefs_->GetDictionary(prefs::kSupervisedUsers);
317 bool SupervisedUserSyncService::UpdateSupervisedUserAvatarIfNeeded(
318 const std::string& id,
319 int avatar_index) {
320 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
321 base::DictionaryValue* dict = update.Get();
322 DCHECK(dict->HasKey(id));
323 base::DictionaryValue* value = NULL;
324 bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
325 DCHECK(success);
327 bool acknowledged = false;
328 value->GetBoolean(SupervisedUserSyncService::kAcknowledged, &acknowledged);
329 std::string name;
330 value->GetString(SupervisedUserSyncService::kName, &name);
331 std::string master_key;
332 value->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
333 std::string signature;
334 value->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
335 &signature);
336 std::string encryption;
337 value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
338 &encryption);
339 std::string chromeos_avatar;
340 value->GetString(SupervisedUserSyncService::kChromeOsAvatar,
341 &chromeos_avatar);
342 std::string chrome_avatar;
343 value->GetString(SupervisedUserSyncService::kChromeAvatar, &chrome_avatar);
344 // The following check is just for safety. We want to avoid that the existing
345 // avatar selection is overwritten. Currently we don't allow the user to
346 // choose a different avatar in the recreation dialog, anyway, if there is
347 // already an avatar selected.
348 #if defined(OS_CHROMEOS)
349 if (!chromeos_avatar.empty() && avatar_index != kNoAvatar)
350 return false;
351 #else
352 if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
353 return false;
354 #endif
356 chrome_avatar = avatar_index == kNoAvatar ?
357 std::string() : BuildAvatarString(avatar_index);
358 #if defined(OS_CHROMEOS)
359 value->SetString(kChromeOsAvatar, chrome_avatar);
360 #else
361 value->SetString(kChromeAvatar, chrome_avatar);
362 #endif
364 if (!sync_processor_)
365 return true;
367 SyncChangeList change_list;
368 change_list.push_back(SyncChange(
369 FROM_HERE,
370 SyncChange::ACTION_UPDATE,
371 CreateLocalSyncData(id, name, acknowledged, master_key,
372 chrome_avatar, chromeos_avatar,
373 signature, encryption)));
374 SyncError error =
375 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
376 DCHECK(!error.IsSet()) << error.ToString();
377 return true;
380 void SupervisedUserSyncService::ClearSupervisedUserAvatar(
381 const std::string& id) {
382 bool cleared = UpdateSupervisedUserAvatarIfNeeded(id, kNoAvatar);
383 DCHECK(cleared);
386 void SupervisedUserSyncService::GetSupervisedUsersAsync(
387 const SupervisedUsersCallback& callback) {
388 // If we are already syncing, just run the callback.
389 if (sync_processor_) {
390 callback.Run(GetSupervisedUsers());
391 return;
394 // Otherwise queue it up until we start syncing.
395 callbacks_.push_back(callback);
398 void SupervisedUserSyncService::Shutdown() {
399 NotifySupervisedUsersSyncingStopped();
402 SyncMergeResult SupervisedUserSyncService::MergeDataAndStartSyncing(
403 ModelType type,
404 const SyncDataList& initial_sync_data,
405 scoped_ptr<SyncChangeProcessor> sync_processor,
406 scoped_ptr<SyncErrorFactory> error_handler) {
407 DCHECK_EQ(SUPERVISED_USERS, type);
408 sync_processor_ = sync_processor.Pass();
409 error_handler_ = error_handler.Pass();
411 SyncChangeList change_list;
412 SyncMergeResult result(SUPERVISED_USERS);
414 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
415 base::DictionaryValue* dict = update.Get();
416 result.set_num_items_before_association(dict->size());
417 std::set<std::string> seen_ids;
418 int num_items_added = 0;
419 int num_items_modified = 0;
420 for (SyncDataList::const_iterator it = initial_sync_data.begin();
421 it != initial_sync_data.end(); ++it) {
422 DCHECK_EQ(SUPERVISED_USERS, it->GetDataType());
423 const ManagedUserSpecifics& supervised_user =
424 it->GetSpecifics().managed_user();
425 base::DictionaryValue* value = new base::DictionaryValue();
426 value->SetString(kName, supervised_user.name());
427 value->SetBoolean(kAcknowledged, supervised_user.acknowledged());
428 value->SetString(kMasterKey, supervised_user.master_key());
429 value->SetString(kChromeAvatar, supervised_user.chrome_avatar());
430 value->SetString(kChromeOsAvatar, supervised_user.chromeos_avatar());
431 value->SetString(kPasswordSignatureKey,
432 supervised_user.password_signature_key());
433 value->SetString(kPasswordEncryptionKey,
434 supervised_user.password_encryption_key());
435 if (dict->HasKey(supervised_user.id()))
436 num_items_modified++;
437 else
438 num_items_added++;
439 dict->SetWithoutPathExpansion(supervised_user.id(), value);
440 seen_ids.insert(supervised_user.id());
443 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
444 if (seen_ids.find(it.key()) != seen_ids.end())
445 continue;
447 change_list.push_back(
448 SyncChange(FROM_HERE,
449 SyncChange::ACTION_ADD,
450 CreateSyncDataFromDictionaryEntry(it.key(), it.value())));
452 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
454 result.set_num_items_modified(num_items_modified);
455 result.set_num_items_added(num_items_added);
456 result.set_num_items_after_association(dict->size());
458 DispatchCallbacks();
460 return result;
463 void SupervisedUserSyncService::StopSyncing(ModelType type) {
464 DCHECK_EQ(SUPERVISED_USERS, type);
465 // The observers may want to change the Sync data, so notify them before
466 // resetting the |sync_processor_|.
467 NotifySupervisedUsersSyncingStopped();
468 sync_processor_.reset();
469 error_handler_.reset();
472 SyncDataList SupervisedUserSyncService::GetAllSyncData(
473 ModelType type) const {
474 SyncDataList data;
475 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
476 base::DictionaryValue* dict = update.Get();
477 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
478 data.push_back(CreateSyncDataFromDictionaryEntry(it.key(), it.value()));
480 return data;
483 SyncError SupervisedUserSyncService::ProcessSyncChanges(
484 const tracked_objects::Location& from_here,
485 const SyncChangeList& change_list) {
486 SyncError error;
487 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUsers);
488 base::DictionaryValue* dict = update.Get();
489 for (SyncChangeList::const_iterator it = change_list.begin();
490 it != change_list.end(); ++it) {
491 SyncData data = it->sync_data();
492 DCHECK_EQ(SUPERVISED_USERS, data.GetDataType());
493 const ManagedUserSpecifics& supervised_user =
494 data.GetSpecifics().managed_user();
495 switch (it->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 it->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::OnLastSignedInUsernameChange() {
545 DCHECK(!sync_processor_);
547 // If the last signed in user changes, we clear all data, to avoid supervised
548 // users from one custodian appearing in another one's profile.
549 prefs_->ClearPref(prefs::kSupervisedUsers);
552 void SupervisedUserSyncService::NotifySupervisedUserAcknowledged(
553 const std::string& supervised_user_id) {
554 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
555 OnSupervisedUserAcknowledged(supervised_user_id));
558 void SupervisedUserSyncService::NotifySupervisedUsersSyncingStopped() {
559 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver, observers_,
560 OnSupervisedUsersSyncingStopped());
563 void SupervisedUserSyncService::NotifySupervisedUsersChanged() {
564 FOR_EACH_OBSERVER(SupervisedUserSyncServiceObserver,
565 observers_,
566 OnSupervisedUsersChanged());
569 void SupervisedUserSyncService::DispatchCallbacks() {
570 const base::DictionaryValue* supervised_users =
571 prefs_->GetDictionary(prefs::kSupervisedUsers);
572 for (std::vector<SupervisedUsersCallback>::iterator it = callbacks_.begin();
573 it != callbacks_.end(); ++it) {
574 it->Run(supervised_users);
576 callbacks_.clear();