supervised_user_shared_settings_service.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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. 4 5#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h" 6 7#include "base/json/json_reader.h" 8#include "base/json/json_writer.h" 9#include "base/prefs/pref_service.h" 10#include "base/prefs/scoped_user_pref_update.h" 11#include "base/values.h" 12#include "chrome/common/pref_names.h" 13#include "components/pref_registry/pref_registry_syncable.h" 14#include "sync/api/sync_change.h" 15#include "sync/api/sync_data.h" 16#include "sync/api/sync_error.h" 17#include "sync/api/sync_error_factory.h" 18#include "sync/api/sync_merge_result.h" 19#include "sync/protocol/sync.pb.h" 20 21using base::DictionaryValue; 22using base::Value; 23using syncer::SUPERVISED_USER_SHARED_SETTINGS; 24using syncer::ModelType; 25using syncer::SyncChange; 26using syncer::SyncChangeList; 27using syncer::SyncChangeProcessor; 28using syncer::SyncData; 29using syncer::SyncDataList; 30using syncer::SyncError; 31using syncer::SyncErrorFactory; 32using syncer::SyncMergeResult; 33 34namespace { 35 36const char kAcknowledged[] = "acknowledged"; 37const char kValue[] = "value"; 38 39DictionaryValue* FindOrCreateDictionary(DictionaryValue* parent, 40 const std::string& key) { 41 DictionaryValue* dict = NULL; 42 if (!parent->GetDictionaryWithoutPathExpansion(key, &dict)) { 43 dict = new DictionaryValue; 44 parent->SetWithoutPathExpansion(key, dict); 45 } 46 return dict; 47} 48 49class ScopedSupervisedUserSharedSettingsUpdate { 50 public: 51 ScopedSupervisedUserSharedSettingsUpdate(PrefService* prefs, 52 const std::string& su_id) 53 : update_(prefs, prefs::kSupervisedUserSharedSettings), su_id_(su_id) { 54 DCHECK(!su_id.empty()); 55 56 // A supervised user can only modify their own settings. 57 std::string id = prefs->GetString(prefs::kSupervisedUserId); 58 DCHECK(id.empty() || id == su_id); 59 } 60 61 DictionaryValue* Get() { 62 return FindOrCreateDictionary(update_.Get(), su_id_); 63 } 64 65 private: 66 DictionaryPrefUpdate update_; 67 std::string su_id_; 68}; 69 70SyncData CreateSyncDataForValue( 71 const std::string& su_id, 72 const std::string& key, 73 const Value& dict_value) { 74 const DictionaryValue* dict = NULL; 75 if (!dict_value.GetAsDictionary(&dict)) 76 return SyncData(); 77 78 const Value* value = NULL; 79 if (!dict->Get(kValue, &value)) 80 return SyncData(); 81 82 bool acknowledged = false; 83 dict->GetBoolean(kAcknowledged, &acknowledged); 84 85 return SupervisedUserSharedSettingsService::CreateSyncDataForSetting( 86 su_id, key, *value, acknowledged); 87} 88 89} // namespace 90 91 92SupervisedUserSharedSettingsService::SupervisedUserSharedSettingsService( 93 PrefService* prefs) 94 : prefs_(prefs) {} 95 96SupervisedUserSharedSettingsService::~SupervisedUserSharedSettingsService() {} 97 98void SupervisedUserSharedSettingsService::SetValueInternal( 99 const std::string& su_id, 100 const std::string& key, 101 const Value& value, 102 bool acknowledged) { 103 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id); 104 DictionaryValue* update_dict = update.Get(); 105 106 DictionaryValue* dict = NULL; 107 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict); 108 if (!has_key) { 109 dict = new DictionaryValue; 110 update_dict->SetWithoutPathExpansion(key, dict); 111 } 112 dict->SetWithoutPathExpansion(kValue, value.DeepCopy()); 113 dict->SetBooleanWithoutPathExpansion(kAcknowledged, acknowledged); 114 115 if (!sync_processor_) 116 return; 117 118 SyncData data = CreateSyncDataForSetting(su_id, key, value, acknowledged); 119 SyncChange::SyncChangeType change_type = 120 has_key ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD; 121 SyncChangeList changes; 122 changes.push_back(SyncChange(FROM_HERE, change_type, data)); 123 SyncError error = sync_processor_->ProcessSyncChanges(FROM_HERE, changes); 124 DCHECK(!error.IsSet()) << error.ToString(); 125} 126 127const Value* SupervisedUserSharedSettingsService::GetValue( 128 const std::string& su_id, 129 const std::string& key) { 130 const DictionaryValue* data = 131 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); 132 const DictionaryValue* dict = NULL; 133 if (!data->GetDictionaryWithoutPathExpansion(su_id, &dict)) 134 return NULL; 135 136 const DictionaryValue* settings = NULL; 137 if (!dict->GetDictionaryWithoutPathExpansion(key, &settings)) 138 return NULL; 139 140 const Value* value = NULL; 141 if (!settings->GetWithoutPathExpansion(kValue, &value)) 142 return NULL; 143 144 return value; 145} 146 147void SupervisedUserSharedSettingsService::SetValue( 148 const std::string& su_id, 149 const std::string& key, 150 const Value& value) { 151 SetValueInternal(su_id, key, value, true); 152} 153 154scoped_ptr< 155 SupervisedUserSharedSettingsService::ChangeCallbackList::Subscription> 156SupervisedUserSharedSettingsService::Subscribe( 157 const SupervisedUserSharedSettingsService::ChangeCallback& cb) { 158 return callbacks_.Add(cb); 159} 160 161// static 162void SupervisedUserSharedSettingsService::RegisterProfilePrefs( 163 user_prefs::PrefRegistrySyncable* registry) { 164 registry->RegisterDictionaryPref( 165 prefs::kSupervisedUserSharedSettings, 166 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 167} 168 169// static 170SyncData SupervisedUserSharedSettingsService::CreateSyncDataForSetting( 171 const std::string& su_id, 172 const std::string& key, 173 const Value& value, 174 bool acknowledged) { 175 std::string json_value; 176 base::JSONWriter::Write(&value, &json_value); 177 ::sync_pb::EntitySpecifics specifics; 178 specifics.mutable_managed_user_shared_setting()->set_mu_id(su_id); 179 specifics.mutable_managed_user_shared_setting()->set_key(key); 180 specifics.mutable_managed_user_shared_setting()->set_value(json_value); 181 specifics.mutable_managed_user_shared_setting()->set_acknowledged( 182 acknowledged); 183 std::string title = su_id + ":" + key; 184 return SyncData::CreateLocalData(title, title, specifics); 185} 186 187void SupervisedUserSharedSettingsService::Shutdown() {} 188 189syncer::SyncMergeResult 190SupervisedUserSharedSettingsService::MergeDataAndStartSyncing( 191 syncer::ModelType type, 192 const syncer::SyncDataList& initial_sync_data, 193 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, 194 scoped_ptr<syncer::SyncErrorFactory> error_handler) { 195 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); 196 sync_processor_ = sync_processor.Pass(); 197 error_handler_ = error_handler.Pass(); 198 199 // We keep a map from MU ID to the set of keys that we have seen in the 200 // initial sync data. 201 std::map<std::string, std::set<std::string> > seen_keys; 202 203 // Iterate over all initial sync data, and update it locally. This means that 204 // the value from the server always wins over a local value. 205 for (SyncDataList::const_iterator it = initial_sync_data.begin(); 206 it != initial_sync_data.end(); 207 ++it) { 208 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, it->GetDataType()); 209 const ::sync_pb::ManagedUserSharedSettingSpecifics& 210 supervised_user_shared_setting = 211 it->GetSpecifics().managed_user_shared_setting(); 212 scoped_ptr<Value> value( 213 base::JSONReader::Read(supervised_user_shared_setting.value())); 214 const std::string& su_id = supervised_user_shared_setting.mu_id(); 215 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id); 216 const std::string& key = supervised_user_shared_setting.key(); 217 DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key); 218 dict->SetWithoutPathExpansion(kValue, value.release()); 219 220 // Every setting we get from the server should have the acknowledged flag 221 // set. 222 DCHECK(supervised_user_shared_setting.acknowledged()); 223 dict->SetBooleanWithoutPathExpansion( 224 kAcknowledged, supervised_user_shared_setting.acknowledged()); 225 callbacks_.Notify(su_id, key); 226 227 seen_keys[su_id].insert(key); 228 } 229 230 // Iterate over all settings that we have locally, which includes settings 231 // that were just synced down. We filter those out using |seen_keys|. 232 SyncChangeList change_list; 233 const DictionaryValue* all_settings = 234 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); 235 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); 236 it.Advance()) { 237 const DictionaryValue* dict = NULL; 238 bool success = it.value().GetAsDictionary(&dict); 239 DCHECK(success); 240 241 const std::set<std::string>& seen = seen_keys[it.key()]; 242 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { 243 // We only need to upload settings that we haven't seen in the initial 244 // sync data (which means they were added locally). 245 if (seen.count(jt.key()) > 0) 246 continue; 247 248 SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value()); 249 DCHECK(data.IsValid()); 250 change_list.push_back( 251 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data)); 252 } 253 } 254 255 SyncMergeResult result(SUPERVISED_USER_SHARED_SETTINGS); 256 // Process all the accumulated changes. 257 if (change_list.size() > 0) { 258 result.set_error( 259 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); 260 } 261 262 // TODO(bauerb): Statistics? 263 return result; 264} 265 266void SupervisedUserSharedSettingsService::StopSyncing(syncer::ModelType type) { 267 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); 268 sync_processor_.reset(); 269 error_handler_.reset(); 270} 271 272syncer::SyncDataList SupervisedUserSharedSettingsService::GetAllSyncData( 273 syncer::ModelType type) const { 274 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); 275 SyncDataList data; 276 const DictionaryValue* all_settings = 277 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); 278 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); 279 it.Advance()) { 280 const DictionaryValue* dict = NULL; 281 bool success = it.value().GetAsDictionary(&dict); 282 DCHECK(success); 283 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { 284 data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value())); 285 } 286 } 287 return data; 288} 289 290syncer::SyncError SupervisedUserSharedSettingsService::ProcessSyncChanges( 291 const tracked_objects::Location& from_here, 292 const syncer::SyncChangeList& change_list) { 293 for (SyncChangeList::const_iterator it = change_list.begin(); 294 it != change_list.end(); 295 ++it) { 296 SyncData data = it->sync_data(); 297 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType()); 298 const ::sync_pb::ManagedUserSharedSettingSpecifics& 299 supervised_user_shared_setting = 300 data.GetSpecifics().managed_user_shared_setting(); 301 const std::string& key = supervised_user_shared_setting.key(); 302 const std::string& su_id = supervised_user_shared_setting.mu_id(); 303 ScopedSupervisedUserSharedSettingsUpdate update(prefs_, su_id); 304 DictionaryValue* update_dict = update.Get(); 305 DictionaryValue* dict = NULL; 306 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict); 307 switch (it->change_type()) { 308 case SyncChange::ACTION_ADD: 309 case SyncChange::ACTION_UPDATE: { 310 // Every setting we get from the server should have the acknowledged 311 // flag set. 312 DCHECK(supervised_user_shared_setting.acknowledged()); 313 314 if (has_key) { 315 // If the supervised user already exists, it should be an update 316 // action. 317 DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type()); 318 } else { 319 // Otherwise, it should be an add action. 320 DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type()); 321 dict = new DictionaryValue; 322 update_dict->SetWithoutPathExpansion(key, dict); 323 } 324 scoped_ptr<Value> value( 325 base::JSONReader::Read(supervised_user_shared_setting.value())); 326 dict->SetWithoutPathExpansion(kValue, value.release()); 327 dict->SetBooleanWithoutPathExpansion( 328 kAcknowledged, supervised_user_shared_setting.acknowledged()); 329 break; 330 } 331 case SyncChange::ACTION_DELETE: { 332 if (has_key) 333 update_dict->RemoveWithoutPathExpansion(key, NULL); 334 else 335 NOTREACHED() << "Trying to delete nonexistent key " << key; 336 break; 337 } 338 case SyncChange::ACTION_INVALID: { 339 NOTREACHED(); 340 break; 341 } 342 } 343 callbacks_.Notify(su_id, key); 344 } 345 346 SyncError error; 347 return error; 348} 349