Home | History | Annotate | Download | only in managed_mode
      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