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 <stddef.h>
8 
9 #include <set>
10 #include <utility>
11 
12 #include "base/callback.h"
13 #include "base/json/json_reader.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/metrics/user_metrics.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "chrome/browser/supervised_user/supervised_user_url_filter.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "components/prefs/json_pref_store.h"
22 #include "components/prefs/pref_filter.h"
23 #include "components/sync/model/sync_change.h"
24 #include "components/sync/model/sync_change_processor.h"
25 #include "components/sync/model/sync_error_factory.h"
26 #include "components/sync/protocol/sync.pb.h"
27 #include "content/public/browser/browser_thread.h"
28 
29 using base::DictionaryValue;
30 using base::JSONReader;
31 using base::UserMetricsAction;
32 using base::Value;
33 using content::BrowserThread;
34 using syncer::ModelError;
35 using syncer::ModelType;
36 using syncer::SUPERVISED_USER_SETTINGS;
37 using syncer::SyncChange;
38 using syncer::SyncChangeList;
39 using syncer::SyncChangeProcessor;
40 using syncer::SyncData;
41 using syncer::SyncDataList;
42 using syncer::SyncErrorFactory;
43 
44 const char kAtomicSettings[] = "atomic_settings";
45 const char kSupervisedUserInternalItemPrefix[] = "X-";
46 const char kQueuedItems[] = "queued_items";
47 const char kSplitSettingKeySeparator = ':';
48 const char kSplitSettings[] = "split_settings";
49 
50 namespace {
51 
SettingShouldApplyToPrefs(const std::string & name)52 bool SettingShouldApplyToPrefs(const std::string& name) {
53   return !base::StartsWith(name, kSupervisedUserInternalItemPrefix,
54                            base::CompareCase::INSENSITIVE_ASCII);
55 }
56 
57 }  // namespace
58 
SupervisedUserSettingsService()59 SupervisedUserSettingsService::SupervisedUserSettingsService()
60     : active_(false),
61       initialization_failed_(false),
62       local_settings_(new base::DictionaryValue) {}
63 
~SupervisedUserSettingsService()64 SupervisedUserSettingsService::~SupervisedUserSettingsService() {}
65 
Init(base::FilePath profile_path,base::SequencedTaskRunner * sequenced_task_runner,bool load_synchronously)66 void SupervisedUserSettingsService::Init(
67     base::FilePath profile_path,
68     base::SequencedTaskRunner* sequenced_task_runner,
69     bool load_synchronously) {
70   base::FilePath path =
71       profile_path.Append(chrome::kSupervisedUserSettingsFilename);
72   PersistentPrefStore* store = new JsonPrefStore(
73       path, std::unique_ptr<PrefFilter>(), sequenced_task_runner);
74   Init(store);
75   if (load_synchronously) {
76     store_->ReadPrefs();
77     DCHECK(IsReady());
78   } else {
79     store_->ReadPrefsAsync(nullptr);
80   }
81 }
82 
Init(scoped_refptr<PersistentPrefStore> store)83 void SupervisedUserSettingsService::Init(
84     scoped_refptr<PersistentPrefStore> store) {
85   DCHECK(!store_.get());
86   store_ = store;
87   store_->AddObserver(this);
88 }
89 
90 std::unique_ptr<
91     SupervisedUserSettingsService::SettingsCallbackList::Subscription>
SubscribeForSettingsChange(const SettingsCallback & callback)92 SupervisedUserSettingsService::SubscribeForSettingsChange(
93     const SettingsCallback& callback) {
94   if (IsReady()) {
95     std::unique_ptr<base::DictionaryValue> settings = GetSettings();
96     callback.Run(settings.get());
97   }
98 
99   return settings_callback_list_.Add(callback);
100 }
101 
102 std::unique_ptr<
103     SupervisedUserSettingsService::ShutdownCallbackList::Subscription>
SubscribeForShutdown(const ShutdownCallback & callback)104 SupervisedUserSettingsService::SubscribeForShutdown(
105     const ShutdownCallback& callback) {
106   return shutdown_callback_list_.Add(callback);
107 }
108 
SetActive(bool active)109 void SupervisedUserSettingsService::SetActive(bool active) {
110   active_ = active;
111   InformSubscribers();
112 }
113 
IsReady() const114 bool SupervisedUserSettingsService::IsReady() const {
115   // Initialization cannot be complete but have failed at the same time.
116   DCHECK(!(store_->IsInitializationComplete() && initialization_failed_));
117   return initialization_failed_ || store_->IsInitializationComplete();
118 }
119 
Clear()120 void SupervisedUserSettingsService::Clear() {
121   store_->RemoveValue(kAtomicSettings,
122                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
123   store_->RemoveValue(kSplitSettings,
124                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
125 }
126 
127 // static
MakeSplitSettingKey(const std::string & prefix,const std::string & key)128 std::string SupervisedUserSettingsService::MakeSplitSettingKey(
129     const std::string& prefix,
130     const std::string& key) {
131   return prefix + kSplitSettingKeySeparator + key;
132 }
133 
UploadItem(const std::string & key,std::unique_ptr<base::Value> value)134 void SupervisedUserSettingsService::UploadItem(
135     const std::string& key,
136     std::unique_ptr<base::Value> value) {
137   DCHECK(!SettingShouldApplyToPrefs(key));
138   PushItemToSync(key, std::move(value));
139 }
140 
PushItemToSync(const std::string & key,std::unique_ptr<base::Value> value)141 void SupervisedUserSettingsService::PushItemToSync(
142     const std::string& key,
143     std::unique_ptr<base::Value> value) {
144   std::string key_suffix = key;
145   base::DictionaryValue* dict = nullptr;
146   if (sync_processor_) {
147     base::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Syncing"));
148     dict = GetDictionaryAndSplitKey(&key_suffix);
149     DCHECK(GetQueuedItems()->empty());
150     SyncChangeList change_list;
151     SyncData data = CreateSyncDataForSetting(key, *value);
152     SyncChange::SyncChangeType change_type =
153         dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
154                                  : SyncChange::ACTION_ADD;
155     change_list.push_back(SyncChange(FROM_HERE, change_type, data));
156     base::Optional<ModelError> error =
157         sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
158     DCHECK(!error.has_value()) << error.value().ToString();
159   } else {
160     // Queue the item up to be uploaded when we start syncing
161     // (in MergeDataAndStartSyncing()).
162     base::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued"));
163     dict = GetQueuedItems();
164   }
165   dict->SetWithoutPathExpansion(key_suffix, std::move(value));
166 }
167 
SetLocalSetting(const std::string & key,std::unique_ptr<base::Value> value)168 void SupervisedUserSettingsService::SetLocalSetting(
169     const std::string& key,
170     std::unique_ptr<base::Value> value) {
171   if (value)
172     local_settings_->SetWithoutPathExpansion(key, std::move(value));
173   else
174     local_settings_->RemoveKey(key);
175 
176   InformSubscribers();
177 }
178 
179 // static
CreateSyncDataForSetting(const std::string & name,const base::Value & value)180 SyncData SupervisedUserSettingsService::CreateSyncDataForSetting(
181     const std::string& name,
182     const base::Value& value) {
183   std::string json_value;
184   base::JSONWriter::Write(value, &json_value);
185   ::sync_pb::EntitySpecifics specifics;
186   specifics.mutable_managed_user_setting()->set_name(name);
187   specifics.mutable_managed_user_setting()->set_value(json_value);
188   return SyncData::CreateLocalData(name, name, specifics);
189 }
190 
Shutdown()191 void SupervisedUserSettingsService::Shutdown() {
192   store_->RemoveObserver(this);
193   shutdown_callback_list_.Notify();
194 }
195 
WaitUntilReadyToSync(base::OnceClosure done)196 void SupervisedUserSettingsService::WaitUntilReadyToSync(
197     base::OnceClosure done) {
198   DCHECK(!wait_until_ready_to_sync_cb_);
199   if (IsReady()) {
200     std::move(done).Run();
201   } else {
202     // Wait until OnInitializationCompleted().
203     wait_until_ready_to_sync_cb_ = std::move(done);
204   }
205 }
206 
207 base::Optional<syncer::ModelError>
MergeDataAndStartSyncing(ModelType type,const SyncDataList & initial_sync_data,std::unique_ptr<SyncChangeProcessor> sync_processor,std::unique_ptr<SyncErrorFactory> error_handler)208 SupervisedUserSettingsService::MergeDataAndStartSyncing(
209     ModelType type,
210     const SyncDataList& initial_sync_data,
211     std::unique_ptr<SyncChangeProcessor> sync_processor,
212     std::unique_ptr<SyncErrorFactory> error_handler) {
213   DCHECK_EQ(SUPERVISED_USER_SETTINGS, type);
214   sync_processor_ = std::move(sync_processor);
215   error_handler_ = std::move(error_handler);
216 
217   std::set<std::string> seen_keys;
218   for (base::DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd();
219        it.Advance()) {
220     seen_keys.insert(it.key());
221   }
222   // Getting number of split setting items.
223   for (base::DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd();
224        it.Advance()) {
225     const base::DictionaryValue* dict = nullptr;
226     it.value().GetAsDictionary(&dict);
227     for (base::DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd();
228          jt.Advance()) {
229       seen_keys.insert(MakeSplitSettingKey(it.key(), jt.key()));
230     }
231   }
232 
233   // Getting number of queued items.
234   base::DictionaryValue* queued_items = GetQueuedItems();
235 
236   // Clear all atomic and split settings, then recreate them from Sync data.
237   Clear();
238   std::set<std::string> added_sync_keys;
239   for (const SyncData& sync_data : initial_sync_data) {
240     DCHECK_EQ(SUPERVISED_USER_SETTINGS, sync_data.GetDataType());
241     const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting =
242         sync_data.GetSpecifics().managed_user_setting();
243     std::unique_ptr<base::Value> value =
244         JSONReader::ReadDeprecated(supervised_user_setting.value());
245     // Wrongly formatted input will cause null values.
246     // SetWithoutPathExpansion below requires non-null values.
247     if (!value) {
248       DLOG(ERROR) << "Invalid managed user setting value: "
249                   << supervised_user_setting.value()
250                   << ". Values must be JSON values.";
251       continue;
252     }
253     std::string name_suffix = supervised_user_setting.name();
254     std::string name_key = name_suffix;
255     base::DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix);
256     dict->SetWithoutPathExpansion(name_suffix, std::move(value));
257     if (seen_keys.find(name_key) == seen_keys.end()) {
258       added_sync_keys.insert(name_key);
259     }
260   }
261 
262   store_->ReportValueChanged(kAtomicSettings,
263                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
264   store_->ReportValueChanged(kSplitSettings,
265                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
266   InformSubscribers();
267 
268   // Upload all the queued up items (either with an ADD or an UPDATE action,
269   // depending on whether they already exist) and move them to split settings.
270   SyncChangeList change_list;
271   for (base::DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd();
272        it.Advance()) {
273     std::string key_suffix = it.key();
274     std::string name_key = key_suffix;
275     base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix);
276     SyncData data = CreateSyncDataForSetting(it.key(), it.value());
277     SyncChange::SyncChangeType change_type =
278         dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE
279                                  : SyncChange::ACTION_ADD;
280     change_list.push_back(SyncChange(FROM_HERE, change_type, data));
281     dict->SetKey(key_suffix, it.value().Clone());
282   }
283   queued_items->Clear();
284 
285   // Process all the accumulated changes from the queued items.
286   if (!change_list.empty()) {
287     store_->ReportValueChanged(kQueuedItems,
288                                WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
289     return sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
290   }
291 
292   return base::nullopt;
293 }
294 
StopSyncing(ModelType type)295 void SupervisedUserSettingsService::StopSyncing(ModelType type) {
296   DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type);
297   sync_processor_.reset();
298   error_handler_.reset();
299 }
300 
GetAllSyncDataForTesting(ModelType type) const301 SyncDataList SupervisedUserSettingsService::GetAllSyncDataForTesting(
302     ModelType type) const {
303   DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type);
304   SyncDataList data;
305   for (base::DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd();
306        it.Advance()) {
307     data.push_back(CreateSyncDataForSetting(it.key(), it.value()));
308   }
309   for (base::DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd();
310        it.Advance()) {
311     const base::DictionaryValue* dict = nullptr;
312     it.value().GetAsDictionary(&dict);
313     for (base::DictionaryValue::Iterator jt(*dict);
314          !jt.IsAtEnd(); jt.Advance()) {
315       data.push_back(CreateSyncDataForSetting(
316           MakeSplitSettingKey(it.key(), jt.key()), jt.value()));
317     }
318   }
319   DCHECK_EQ(0u, GetQueuedItems()->size());
320   return data;
321 }
322 
323 base::Optional<syncer::ModelError>
ProcessSyncChanges(const base::Location & from_here,const SyncChangeList & change_list)324 SupervisedUserSettingsService::ProcessSyncChanges(
325     const base::Location& from_here,
326     const SyncChangeList& change_list) {
327   for (const SyncChange& sync_change : change_list) {
328     SyncData data = sync_change.sync_data();
329     DCHECK_EQ(SUPERVISED_USER_SETTINGS, data.GetDataType());
330     const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting =
331         data.GetSpecifics().managed_user_setting();
332     std::string key = supervised_user_setting.name();
333     base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key);
334     SyncChange::SyncChangeType change_type = sync_change.change_type();
335     switch (change_type) {
336       case SyncChange::ACTION_ADD:
337       case SyncChange::ACTION_UPDATE: {
338         std::unique_ptr<base::Value> value =
339             JSONReader::ReadDeprecated(supervised_user_setting.value());
340         if (dict->HasKey(key)) {
341           DLOG_IF(WARNING, change_type == SyncChange::ACTION_ADD)
342               << "Value for key " << key << " already exists";
343         } else {
344           DLOG_IF(WARNING, change_type == SyncChange::ACTION_UPDATE)
345               << "Value for key " << key << " doesn't exist yet";
346         }
347         dict->SetWithoutPathExpansion(key, std::move(value));
348         break;
349       }
350       case SyncChange::ACTION_DELETE: {
351         DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent "
352                                              << "key " << key;
353         dict->RemoveKey(key);
354         break;
355       }
356       case SyncChange::ACTION_INVALID: {
357         NOTREACHED();
358         break;
359       }
360     }
361   }
362   store_->ReportValueChanged(kAtomicSettings,
363                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
364   store_->ReportValueChanged(kSplitSettings,
365                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
366   InformSubscribers();
367 
368   return base::nullopt;
369 }
370 
OnPrefValueChanged(const std::string & key)371 void SupervisedUserSettingsService::OnPrefValueChanged(const std::string& key) {
372 }
373 
OnInitializationCompleted(bool success)374 void SupervisedUserSettingsService::OnInitializationCompleted(bool success) {
375   if (!success) {
376     // If this happens, it means the profile directory was not found. There is
377     // not much we can do, but the whole profile will probably be useless
378     // anyway. Just mark initialization as failed and continue otherwise,
379     // because subscribers might still expect to be called back.
380     initialization_failed_ = true;
381   }
382 
383   DCHECK(IsReady());
384 
385   if (wait_until_ready_to_sync_cb_)
386     std::move(wait_until_ready_to_sync_cb_).Run();
387 
388   InformSubscribers();
389 }
390 
391 const base::DictionaryValue*
LocalSettingsForTest() const392 SupervisedUserSettingsService::LocalSettingsForTest() const {
393   return local_settings_.get();
394 }
395 
GetDictionaryAndSplitKey(std::string * key) const396 base::DictionaryValue* SupervisedUserSettingsService::GetDictionaryAndSplitKey(
397     std::string* key) const {
398   size_t pos = key->find_first_of(kSplitSettingKeySeparator);
399   if (pos == std::string::npos)
400     return GetAtomicSettings();
401 
402   base::DictionaryValue* split_settings = GetSplitSettings();
403   std::string prefix = key->substr(0, pos);
404   base::DictionaryValue* dict = nullptr;
405   if (!split_settings->GetDictionary(prefix, &dict)) {
406     DCHECK(!split_settings->HasKey(prefix));
407     dict = split_settings->SetDictionary(
408         prefix, std::make_unique<base::DictionaryValue>());
409   }
410   key->erase(0, pos + 1);
411   return dict;
412 }
413 
GetOrCreateDictionary(const std::string & key) const414 base::DictionaryValue* SupervisedUserSettingsService::GetOrCreateDictionary(
415     const std::string& key) const {
416   base::Value* value = nullptr;
417   if (!store_->GetMutableValue(key, &value)) {
418     store_->SetValue(
419         key, std::make_unique<base::Value>(base::Value::Type::DICTIONARY),
420         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
421     store_->GetMutableValue(key, &value);
422   }
423   base::DictionaryValue* dict = nullptr;
424   bool success = value->GetAsDictionary(&dict);
425   DCHECK(success);
426   return dict;
427 }
428 
429 base::DictionaryValue*
GetAtomicSettings() const430 SupervisedUserSettingsService::GetAtomicSettings() const {
431   return GetOrCreateDictionary(kAtomicSettings);
432 }
433 
GetSplitSettings() const434 base::DictionaryValue* SupervisedUserSettingsService::GetSplitSettings() const {
435   return GetOrCreateDictionary(kSplitSettings);
436 }
437 
GetQueuedItems() const438 base::DictionaryValue* SupervisedUserSettingsService::GetQueuedItems() const {
439   return GetOrCreateDictionary(kQueuedItems);
440 }
441 
442 std::unique_ptr<base::DictionaryValue>
GetSettings()443 SupervisedUserSettingsService::GetSettings() {
444   DCHECK(IsReady());
445   if (!active_ || initialization_failed_)
446     return std::unique_ptr<base::DictionaryValue>();
447 
448   std::unique_ptr<base::DictionaryValue> settings(local_settings_->DeepCopy());
449 
450   base::DictionaryValue* atomic_settings = GetAtomicSettings();
451   for (base::DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd();
452        it.Advance()) {
453     if (!SettingShouldApplyToPrefs(it.key()))
454       continue;
455 
456     settings->Set(it.key(), std::make_unique<base::Value>(it.value().Clone()));
457   }
458 
459   base::DictionaryValue* split_settings = GetSplitSettings();
460   for (base::DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd();
461        it.Advance()) {
462     if (!SettingShouldApplyToPrefs(it.key()))
463       continue;
464 
465     settings->Set(it.key(), std::make_unique<base::Value>(it.value().Clone()));
466   }
467 
468   return settings;
469 }
470 
InformSubscribers()471 void SupervisedUserSettingsService::InformSubscribers() {
472   if (!IsReady())
473     return;
474 
475   std::unique_ptr<base::DictionaryValue> settings = GetSettings();
476   settings_callback_list_.Notify(settings.get());
477 }
478