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_settings_service.h" 6 7 #include "base/callback.h" 8 #include "base/json/json_reader.h" 9 #include "base/json/json_writer.h" 10 #include "base/prefs/json_pref_store.h" 11 #include "base/strings/string_util.h" 12 #include "base/threading/sequenced_worker_pool.h" 13 #include "chrome/browser/managed_mode/managed_mode_url_filter.h" 14 #include "chrome/common/chrome_constants.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/user_metrics.h" 17 #include "sync/api/sync_change.h" 18 #include "sync/api/sync_error_factory.h" 19 #include "sync/protocol/sync.pb.h" 20 21 using base::DictionaryValue; 22 using base::JSONReader; 23 using base::Value; 24 using content::BrowserThread; 25 using content::UserMetricsAction; 26 using syncer::MANAGED_USER_SETTINGS; 27 using syncer::ModelType; 28 using syncer::SyncChange; 29 using syncer::SyncChangeList; 30 using syncer::SyncChangeProcessor; 31 using syncer::SyncData; 32 using syncer::SyncDataList; 33 using syncer::SyncError; 34 using syncer::SyncErrorFactory; 35 using syncer::SyncMergeResult; 36 37 const char kAtomicSettings[] = "atomic_settings"; 38 const char kManagedUserInternalItemPrefix[] = "X-"; 39 const char kQueuedItems[] = "queued_items"; 40 const char kSplitSettingKeySeparator = ':'; 41 const char kSplitSettings[] = "split_settings"; 42 43 namespace { 44 45 bool SettingShouldApplyToPrefs(const std::string& name) { 46 return !StartsWithASCII(name, kManagedUserInternalItemPrefix, false); 47 } 48 49 } // namespace 50 51 ManagedUserSettingsService::ManagedUserSettingsService() 52 : active_(false), local_settings_(new DictionaryValue) {} 53 54 ManagedUserSettingsService::~ManagedUserSettingsService() {} 55 56 void ManagedUserSettingsService::Init( 57 base::FilePath profile_path, 58 base::SequencedTaskRunner* sequenced_task_runner, 59 bool load_synchronously) { 60 base::FilePath path = 61 profile_path.Append(chrome::kManagedUserSettingsFilename); 62 PersistentPrefStore* store = new JsonPrefStore(path, sequenced_task_runner); 63 Init(store); 64 if (load_synchronously) 65 store_->ReadPrefs(); 66 else 67 store_->ReadPrefsAsync(NULL); 68 } 69 70 void ManagedUserSettingsService::Init( 71 scoped_refptr<PersistentPrefStore> store) { 72 DCHECK(!store_); 73 store_ = store; 74 store_->AddObserver(this); 75 } 76 77 void ManagedUserSettingsService::Subscribe(const SettingsCallback& callback) { 78 if (IsReady()) { 79 scoped_ptr<base::DictionaryValue> settings = GetSettings(); 80 callback.Run(settings.get()); 81 } 82 83 subscribers_.push_back(callback); 84 } 85 86 void ManagedUserSettingsService::Activate() { 87 active_ = true; 88 InformSubscribers(); 89 } 90 91 bool ManagedUserSettingsService::IsReady() { 92 return store_->IsInitializationComplete(); 93 } 94 95 void ManagedUserSettingsService::Clear() { 96 store_->RemoveValue(kAtomicSettings); 97 store_->RemoveValue(kSplitSettings); 98 } 99 100 // static 101 std::string ManagedUserSettingsService::MakeSplitSettingKey( 102 const std::string& prefix, 103 const std::string& key) { 104 return prefix + kSplitSettingKeySeparator + key; 105 } 106 107 void ManagedUserSettingsService::UploadItem(const std::string& key, 108 scoped_ptr<Value> value) { 109 DCHECK(!SettingShouldApplyToPrefs(key)); 110 111 std::string key_suffix = key; 112 DictionaryValue* dict = NULL; 113 if (sync_processor_) { 114 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Syncing")); 115 dict = GetDictionaryAndSplitKey(&key_suffix); 116 DCHECK(GetQueuedItems()->empty()); 117 SyncChangeList change_list; 118 SyncData data = CreateSyncDataForSetting(key, *value); 119 SyncChange::SyncChangeType change_type = 120 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE 121 : SyncChange::ACTION_ADD; 122 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); 123 SyncError error = 124 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); 125 DCHECK(!error.IsSet()) << error.ToString(); 126 } else { 127 // Queue the item up to be uploaded when we start syncing 128 // (in MergeDataAndStartSyncing()). 129 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued")); 130 dict = GetQueuedItems(); 131 } 132 dict->SetWithoutPathExpansion(key_suffix, value.release()); 133 } 134 135 void ManagedUserSettingsService::SetLocalSettingForTesting( 136 const std::string& key, 137 scoped_ptr<Value> value) { 138 if (value) 139 local_settings_->SetWithoutPathExpansion(key, value.release()); 140 else 141 local_settings_->RemoveWithoutPathExpansion(key, NULL); 142 143 InformSubscribers(); 144 } 145 146 // static 147 SyncData ManagedUserSettingsService::CreateSyncDataForSetting( 148 const std::string& name, 149 const Value& value) { 150 std::string json_value; 151 base::JSONWriter::Write(&value, &json_value); 152 ::sync_pb::EntitySpecifics specifics; 153 specifics.mutable_managed_user_setting()->set_name(name); 154 specifics.mutable_managed_user_setting()->set_value(json_value); 155 return SyncData::CreateLocalData(name, name, specifics); 156 } 157 158 void ManagedUserSettingsService::Shutdown() { 159 store_->RemoveObserver(this); 160 } 161 162 SyncMergeResult ManagedUserSettingsService::MergeDataAndStartSyncing( 163 ModelType type, 164 const SyncDataList& initial_sync_data, 165 scoped_ptr<SyncChangeProcessor> sync_processor, 166 scoped_ptr<SyncErrorFactory> error_handler) { 167 DCHECK_EQ(MANAGED_USER_SETTINGS, type); 168 sync_processor_ = sync_processor.Pass(); 169 error_handler_ = error_handler.Pass(); 170 171 // Clear all atomic and split settings, then recreate them from Sync data. 172 Clear(); 173 for (SyncDataList::const_iterator it = initial_sync_data.begin(); 174 it != initial_sync_data.end(); ++it) { 175 DCHECK_EQ(MANAGED_USER_SETTINGS, it->GetDataType()); 176 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = 177 it->GetSpecifics().managed_user_setting(); 178 scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value())); 179 std::string name_suffix = managed_user_setting.name(); 180 DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix); 181 dict->SetWithoutPathExpansion(name_suffix, value.release()); 182 } 183 store_->ReportValueChanged(kAtomicSettings); 184 store_->ReportValueChanged(kSplitSettings); 185 InformSubscribers(); 186 187 // Upload all the queued up items (either with an ADD or an UPDATE action, 188 // depending on whether they already exist) and move them to split settings. 189 SyncChangeList change_list; 190 DictionaryValue* queued_items = GetQueuedItems(); 191 for (DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd(); 192 it.Advance()) { 193 std::string key_suffix = it.key(); 194 DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix); 195 SyncData data = CreateSyncDataForSetting(it.key(), it.value()); 196 SyncChange::SyncChangeType change_type = 197 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE 198 : SyncChange::ACTION_ADD; 199 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); 200 dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy()); 201 } 202 queued_items->Clear(); 203 204 SyncMergeResult result(MANAGED_USER_SETTINGS); 205 // Process all the accumulated changes from the queued items. 206 if (change_list.size() > 0) { 207 store_->ReportValueChanged(kQueuedItems); 208 result.set_error( 209 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); 210 } 211 212 // TODO(bauerb): Statistics? 213 return result; 214 } 215 216 void ManagedUserSettingsService::StopSyncing(ModelType type) { 217 DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type); 218 sync_processor_.reset(); 219 error_handler_.reset(); 220 } 221 222 SyncDataList ManagedUserSettingsService::GetAllSyncData( 223 ModelType type) const { 224 DCHECK_EQ(syncer::MANAGED_USER_SETTINGS, type); 225 SyncDataList data; 226 for (DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd(); 227 it.Advance()) { 228 data.push_back(CreateSyncDataForSetting(it.key(), it.value())); 229 } 230 for (DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd(); 231 it.Advance()) { 232 const DictionaryValue* dict = NULL; 233 it.value().GetAsDictionary(&dict); 234 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { 235 data.push_back(CreateSyncDataForSetting( 236 MakeSplitSettingKey(it.key(), jt.key()), jt.value())); 237 } 238 } 239 DCHECK_EQ(0u, GetQueuedItems()->size()); 240 return data; 241 } 242 243 SyncError ManagedUserSettingsService::ProcessSyncChanges( 244 const tracked_objects::Location& from_here, 245 const SyncChangeList& change_list) { 246 for (SyncChangeList::const_iterator it = change_list.begin(); 247 it != change_list.end(); ++it) { 248 SyncData data = it->sync_data(); 249 DCHECK_EQ(MANAGED_USER_SETTINGS, data.GetDataType()); 250 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = 251 data.GetSpecifics().managed_user_setting(); 252 std::string key = managed_user_setting.name(); 253 DictionaryValue* dict = GetDictionaryAndSplitKey(&key); 254 switch (it->change_type()) { 255 case SyncChange::ACTION_ADD: 256 case SyncChange::ACTION_UPDATE: { 257 scoped_ptr<Value> value(JSONReader::Read(managed_user_setting.value())); 258 if (dict->HasKey(key)) { 259 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD) 260 << "Value for key " << key << " already exists"; 261 } else { 262 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE) 263 << "Value for key " << key << " doesn't exist yet"; 264 } 265 dict->SetWithoutPathExpansion(key, value.release()); 266 break; 267 } 268 case SyncChange::ACTION_DELETE: { 269 DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent " 270 << "key " << key; 271 dict->RemoveWithoutPathExpansion(key, NULL); 272 break; 273 } 274 case SyncChange::ACTION_INVALID: { 275 NOTREACHED(); 276 break; 277 } 278 } 279 } 280 store_->ReportValueChanged(kAtomicSettings); 281 store_->ReportValueChanged(kSplitSettings); 282 InformSubscribers(); 283 284 SyncError error; 285 return error; 286 } 287 288 void ManagedUserSettingsService::OnPrefValueChanged(const std::string& key) {} 289 290 void ManagedUserSettingsService::OnInitializationCompleted(bool success) { 291 DCHECK(success); 292 DCHECK(IsReady()); 293 InformSubscribers(); 294 } 295 296 DictionaryValue* ManagedUserSettingsService::GetOrCreateDictionary( 297 const std::string& key) const { 298 Value* value = NULL; 299 DictionaryValue* dict = NULL; 300 if (store_->GetMutableValue(key, &value)) { 301 bool success = value->GetAsDictionary(&dict); 302 DCHECK(success); 303 } else { 304 dict = new base::DictionaryValue; 305 store_->SetValue(key, dict); 306 } 307 308 return dict; 309 } 310 311 DictionaryValue* ManagedUserSettingsService::GetAtomicSettings() const { 312 return GetOrCreateDictionary(kAtomicSettings); 313 } 314 315 DictionaryValue* ManagedUserSettingsService::GetSplitSettings() const { 316 return GetOrCreateDictionary(kSplitSettings); 317 } 318 319 DictionaryValue* ManagedUserSettingsService::GetQueuedItems() const { 320 return GetOrCreateDictionary(kQueuedItems); 321 } 322 323 DictionaryValue* ManagedUserSettingsService::GetDictionaryAndSplitKey( 324 std::string* key) const { 325 size_t pos = key->find_first_of(kSplitSettingKeySeparator); 326 if (pos == std::string::npos) 327 return GetAtomicSettings(); 328 329 DictionaryValue* split_settings = GetSplitSettings(); 330 std::string prefix = key->substr(0, pos); 331 DictionaryValue* dict = NULL; 332 if (!split_settings->GetDictionary(prefix, &dict)) { 333 dict = new DictionaryValue; 334 DCHECK(!split_settings->HasKey(prefix)); 335 split_settings->Set(prefix, dict); 336 } 337 key->erase(0, pos + 1); 338 return dict; 339 } 340 341 scoped_ptr<DictionaryValue> ManagedUserSettingsService::GetSettings() { 342 DCHECK(IsReady()); 343 if (!active_) 344 return scoped_ptr<base::DictionaryValue>(); 345 346 scoped_ptr<DictionaryValue> settings(local_settings_->DeepCopy()); 347 348 DictionaryValue* atomic_settings = GetAtomicSettings(); 349 for (DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd(); 350 it.Advance()) { 351 if (!SettingShouldApplyToPrefs(it.key())) 352 continue; 353 354 settings->Set(it.key(), it.value().DeepCopy()); 355 } 356 357 DictionaryValue* split_settings = GetSplitSettings(); 358 for (DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd(); 359 it.Advance()) { 360 if (!SettingShouldApplyToPrefs(it.key())) 361 continue; 362 363 settings->Set(it.key(), it.value().DeepCopy()); 364 } 365 366 return settings.Pass(); 367 } 368 369 void ManagedUserSettingsService::InformSubscribers() { 370 if (!IsReady()) 371 return; 372 373 scoped_ptr<base::DictionaryValue> settings = GetSettings(); 374 for (std::vector<SettingsCallback>::iterator it = subscribers_.begin(); 375 it != subscribers_.end(); ++it) { 376 it->Run(settings.get()); 377 } 378 } 379