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