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. 4 5 #include "chrome/browser/managed_mode/managed_user_sync_service.h" 6 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" 21 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; 35 36 namespace { 37 38 #if defined(OS_CHROMEOS) 39 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:"; 40 #else 41 const char kChromeAvatarPrefix[] = "chrome-avatar-index:"; 42 #endif 43 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); 62 } 63 64 SyncData CreateSyncDataFromDictionaryEntry( 65 const DictionaryValue::Iterator& it) { 66 const 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); 80 81 return CreateLocalSyncData(it.key(), name, acknowledged, master_key, 82 chrome_avatar, chromeos_avatar); 83 } 84 85 } // namespace 86 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; 93 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))); 101 } 102 103 ManagedUserSyncService::~ManagedUserSyncService() { 104 } 105 106 // static 107 void ManagedUserSyncService::RegisterProfilePrefs( 108 PrefRegistrySyncable* registry) { 109 registry->RegisterDictionaryPref(prefs::kManagedUsers, 110 PrefRegistrySyncable::UNSYNCABLE_PREF); 111 } 112 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; 120 } 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; 130 } 131 132 return base::StringToInt(avatar_str.substr(prefix_len), avatar_index); 133 } 134 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); 143 } 144 145 void ManagedUserSyncService::AddObserver( 146 ManagedUserSyncServiceObserver* observer) { 147 observers_.AddObserver(observer); 148 } 149 150 void ManagedUserSyncService::RemoveObserver( 151 ManagedUserSyncServiceObserver* observer) { 152 observers_.RemoveObserver(observer); 153 } 154 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 DictionaryValue* dict = update.Get(); 161 DictionaryValue* value = new 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); 175 176 if (!sync_processor_) 177 return; 178 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(); 189 } 190 191 void ManagedUserSyncService::DeleteManagedUser(const std::string& id) { 192 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 193 bool success = update->RemoveWithoutPathExpansion(id, NULL); 194 DCHECK(success); 195 196 if (!sync_processor_) 197 return; 198 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()); 207 } 208 209 const DictionaryValue* ManagedUserSyncService::GetManagedUsers() { 210 DCHECK(sync_processor_); 211 return prefs_->GetDictionary(prefs::kManagedUsers); 212 } 213 214 bool ManagedUserSyncService::UpdateManagedUserAvatarIfNeeded( 215 const std::string& id, 216 int avatar_index) { 217 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 218 DictionaryValue* dict = update.Get(); 219 DCHECK(dict->HasKey(id)); 220 DictionaryValue* value = NULL; 221 bool success = dict->GetDictionaryWithoutPathExpansion(id, &value); 222 DCHECK(success); 223 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 245 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 253 254 if (!sync_processor_) 255 return true; 256 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; 267 } 268 269 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string& id) { 270 bool cleared = UpdateManagedUserAvatarIfNeeded(id, kNoAvatar); 271 DCHECK(cleared); 272 } 273 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; 280 } 281 282 // Otherwise queue it up until we start syncing. 283 callbacks_.push_back(callback); 284 } 285 286 void ManagedUserSyncService::Shutdown() { 287 NotifyManagedUsersSyncingStopped(); 288 } 289 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(); 298 299 SyncChangeList change_list; 300 SyncMergeResult result(MANAGED_USERS); 301 302 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 303 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 DictionaryValue* value = new 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()); 325 } 326 327 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { 328 if (seen_ids.find(it.key()) != seen_ids.end()) 329 continue; 330 331 change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD, 332 CreateSyncDataFromDictionaryEntry(it))); 333 } 334 result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); 335 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()); 339 340 DispatchCallbacks(); 341 342 return result; 343 } 344 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(); 352 } 353 354 SyncDataList ManagedUserSyncService::GetAllSyncData( 355 ModelType type) const { 356 SyncDataList data; 357 DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers); 358 DictionaryValue* dict = update.Get(); 359 for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) 360 data.push_back(CreateSyncDataFromDictionaryEntry(it)); 361 362 return data; 363 } 364 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 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 DictionaryValue* old_value = NULL; 383 dict->GetDictionaryWithoutPathExpansion(managed_user.id(), &old_value); 384 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()); 390 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()); 395 396 DictionaryValue* value = new 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; 404 } 405 case SyncChange::ACTION_DELETE: { 406 DCHECK(dict->HasKey(managed_user.id())) << managed_user.id(); 407 dict->RemoveWithoutPathExpansion(managed_user.id(), NULL); 408 break; 409 } 410 case SyncChange::ACTION_INVALID: { 411 NOTREACHED(); 412 break; 413 } 414 } 415 } 416 return error; 417 } 418 419 void ManagedUserSyncService::OnLastSignedInUsernameChange() { 420 DCHECK(!sync_processor_); 421 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); 425 } 426 427 void ManagedUserSyncService::NotifyManagedUserAcknowledged( 428 const std::string& managed_user_id) { 429 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_, 430 OnManagedUserAcknowledged(managed_user_id)); 431 } 432 433 void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() { 434 FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_, 435 OnManagedUsersSyncingStopped()); 436 } 437 438 void ManagedUserSyncService::DispatchCallbacks() { 439 const 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); 444 } 445 callbacks_.clear(); 446 } 447