OLD | NEW |
| (Empty) |
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/managed_mode/managed_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 | |
21 using base::DictionaryValue; | |
22 using base::Value; | |
23 using syncer::SUPERVISED_USER_SHARED_SETTINGS; | |
24 using syncer::ModelType; | |
25 using syncer::SyncChange; | |
26 using syncer::SyncChangeList; | |
27 using syncer::SyncChangeProcessor; | |
28 using syncer::SyncData; | |
29 using syncer::SyncDataList; | |
30 using syncer::SyncError; | |
31 using syncer::SyncErrorFactory; | |
32 using syncer::SyncMergeResult; | |
33 | |
34 namespace { | |
35 | |
36 const char kAcknowledged[] = "acknowledged"; | |
37 const char kValue[] = "value"; | |
38 | |
39 DictionaryValue* 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 | |
49 class ScopedManagedUserSharedSettingsUpdate { | |
50 public: | |
51 ScopedManagedUserSharedSettingsUpdate(PrefService* prefs, | |
52 const std::string& mu_id) | |
53 : update_(prefs, prefs::kSupervisedUserSharedSettings), mu_id_(mu_id) { | |
54 DCHECK(!mu_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 == mu_id); | |
59 } | |
60 | |
61 DictionaryValue* Get() { | |
62 return FindOrCreateDictionary(update_.Get(), mu_id_); | |
63 } | |
64 | |
65 private: | |
66 DictionaryPrefUpdate update_; | |
67 std::string mu_id_; | |
68 }; | |
69 | |
70 SyncData CreateSyncDataForValue( | |
71 const std::string& mu_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 ManagedUserSharedSettingsService::CreateSyncDataForSetting( | |
86 mu_id, key, *value, acknowledged); | |
87 } | |
88 | |
89 } // namespace | |
90 | |
91 | |
92 ManagedUserSharedSettingsService::ManagedUserSharedSettingsService( | |
93 PrefService* prefs) | |
94 : prefs_(prefs) {} | |
95 | |
96 ManagedUserSharedSettingsService::~ManagedUserSharedSettingsService() {} | |
97 | |
98 void ManagedUserSharedSettingsService::SetValueInternal( | |
99 const std::string& mu_id, | |
100 const std::string& key, | |
101 const Value& value, | |
102 bool acknowledged) { | |
103 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_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(mu_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 | |
127 const Value* ManagedUserSharedSettingsService::GetValue( | |
128 const std::string& mu_id, | |
129 const std::string& key) { | |
130 const DictionaryValue* data = | |
131 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); | |
132 const DictionaryValue* dict = NULL; | |
133 if (!data->GetDictionaryWithoutPathExpansion(mu_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 | |
147 void ManagedUserSharedSettingsService::SetValue( | |
148 const std::string& mu_id, | |
149 const std::string& key, | |
150 const Value& value) { | |
151 SetValueInternal(mu_id, key, value, true); | |
152 } | |
153 | |
154 scoped_ptr<ManagedUserSharedSettingsService::ChangeCallbackList::Subscription> | |
155 ManagedUserSharedSettingsService::Subscribe( | |
156 const ManagedUserSharedSettingsService::ChangeCallback& cb) { | |
157 return callbacks_.Add(cb); | |
158 } | |
159 | |
160 // static | |
161 void ManagedUserSharedSettingsService::RegisterProfilePrefs( | |
162 user_prefs::PrefRegistrySyncable* registry) { | |
163 registry->RegisterDictionaryPref( | |
164 prefs::kSupervisedUserSharedSettings, | |
165 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
166 } | |
167 | |
168 // static | |
169 SyncData ManagedUserSharedSettingsService::CreateSyncDataForSetting( | |
170 const std::string& mu_id, | |
171 const std::string& key, | |
172 const Value& value, | |
173 bool acknowledged) { | |
174 std::string json_value; | |
175 base::JSONWriter::Write(&value, &json_value); | |
176 ::sync_pb::EntitySpecifics specifics; | |
177 specifics.mutable_managed_user_shared_setting()->set_mu_id(mu_id); | |
178 specifics.mutable_managed_user_shared_setting()->set_key(key); | |
179 specifics.mutable_managed_user_shared_setting()->set_value(json_value); | |
180 specifics.mutable_managed_user_shared_setting()->set_acknowledged( | |
181 acknowledged); | |
182 std::string title = mu_id + ":" + key; | |
183 return SyncData::CreateLocalData(title, title, specifics); | |
184 } | |
185 | |
186 void ManagedUserSharedSettingsService::Shutdown() {} | |
187 | |
188 syncer::SyncMergeResult | |
189 ManagedUserSharedSettingsService::MergeDataAndStartSyncing( | |
190 syncer::ModelType type, | |
191 const syncer::SyncDataList& initial_sync_data, | |
192 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | |
193 scoped_ptr<syncer::SyncErrorFactory> error_handler) { | |
194 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); | |
195 sync_processor_ = sync_processor.Pass(); | |
196 error_handler_ = error_handler.Pass(); | |
197 | |
198 // We keep a map from MU ID to the set of keys that we have seen in the | |
199 // initial sync data. | |
200 std::map<std::string, std::set<std::string> > seen_keys; | |
201 | |
202 // Iterate over all initial sync data, and update it locally. This means that | |
203 // the value from the server always wins over a local value. | |
204 for (SyncDataList::const_iterator it = initial_sync_data.begin(); | |
205 it != initial_sync_data.end(); | |
206 ++it) { | |
207 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, it->GetDataType()); | |
208 const ::sync_pb::ManagedUserSharedSettingSpecifics& | |
209 managed_user_shared_setting = | |
210 it->GetSpecifics().managed_user_shared_setting(); | |
211 scoped_ptr<Value> value( | |
212 base::JSONReader::Read(managed_user_shared_setting.value())); | |
213 const std::string& mu_id = managed_user_shared_setting.mu_id(); | |
214 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id); | |
215 const std::string& key = managed_user_shared_setting.key(); | |
216 DictionaryValue* dict = FindOrCreateDictionary(update.Get(), key); | |
217 dict->SetWithoutPathExpansion(kValue, value.release()); | |
218 | |
219 // Every setting we get from the server should have the acknowledged flag | |
220 // set. | |
221 DCHECK(managed_user_shared_setting.acknowledged()); | |
222 dict->SetBooleanWithoutPathExpansion( | |
223 kAcknowledged, managed_user_shared_setting.acknowledged()); | |
224 callbacks_.Notify(mu_id, key); | |
225 | |
226 seen_keys[mu_id].insert(key); | |
227 } | |
228 | |
229 // Iterate over all settings that we have locally, which includes settings | |
230 // that were just synced down. We filter those out using |seen_keys|. | |
231 SyncChangeList change_list; | |
232 const DictionaryValue* all_settings = | |
233 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); | |
234 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); | |
235 it.Advance()) { | |
236 const DictionaryValue* dict = NULL; | |
237 bool success = it.value().GetAsDictionary(&dict); | |
238 DCHECK(success); | |
239 | |
240 const std::set<std::string>& seen = seen_keys[it.key()]; | |
241 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { | |
242 // We only need to upload settings that we haven't seen in the initial | |
243 // sync data (which means they were added locally). | |
244 if (seen.count(jt.key()) > 0) | |
245 continue; | |
246 | |
247 SyncData data = CreateSyncDataForValue(it.key(), jt.key(), jt.value()); | |
248 DCHECK(data.IsValid()); | |
249 change_list.push_back( | |
250 SyncChange(FROM_HERE, SyncChange::ACTION_ADD, data)); | |
251 } | |
252 } | |
253 | |
254 SyncMergeResult result(SUPERVISED_USER_SHARED_SETTINGS); | |
255 // Process all the accumulated changes. | |
256 if (change_list.size() > 0) { | |
257 result.set_error( | |
258 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); | |
259 } | |
260 | |
261 // TODO(bauerb): Statistics? | |
262 return result; | |
263 } | |
264 | |
265 void ManagedUserSharedSettingsService::StopSyncing(syncer::ModelType type) { | |
266 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); | |
267 sync_processor_.reset(); | |
268 error_handler_.reset(); | |
269 } | |
270 | |
271 syncer::SyncDataList ManagedUserSharedSettingsService::GetAllSyncData( | |
272 syncer::ModelType type) const { | |
273 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, type); | |
274 SyncDataList data; | |
275 const DictionaryValue* all_settings = | |
276 prefs_->GetDictionary(prefs::kSupervisedUserSharedSettings); | |
277 for (DictionaryValue::Iterator it(*all_settings); !it.IsAtEnd(); | |
278 it.Advance()) { | |
279 const DictionaryValue* dict = NULL; | |
280 bool success = it.value().GetAsDictionary(&dict); | |
281 DCHECK(success); | |
282 for (DictionaryValue::Iterator jt(*dict); !jt.IsAtEnd(); jt.Advance()) { | |
283 data.push_back(CreateSyncDataForValue(it.key(), jt.key(), jt.value())); | |
284 } | |
285 } | |
286 return data; | |
287 } | |
288 | |
289 syncer::SyncError ManagedUserSharedSettingsService::ProcessSyncChanges( | |
290 const tracked_objects::Location& from_here, | |
291 const syncer::SyncChangeList& change_list) { | |
292 for (SyncChangeList::const_iterator it = change_list.begin(); | |
293 it != change_list.end(); | |
294 ++it) { | |
295 SyncData data = it->sync_data(); | |
296 DCHECK_EQ(SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType()); | |
297 const ::sync_pb::ManagedUserSharedSettingSpecifics& | |
298 managed_user_shared_setting = | |
299 data.GetSpecifics().managed_user_shared_setting(); | |
300 const std::string& key = managed_user_shared_setting.key(); | |
301 const std::string& mu_id = managed_user_shared_setting.mu_id(); | |
302 ScopedManagedUserSharedSettingsUpdate update(prefs_, mu_id); | |
303 DictionaryValue* update_dict = update.Get(); | |
304 DictionaryValue* dict = NULL; | |
305 bool has_key = update_dict->GetDictionaryWithoutPathExpansion(key, &dict); | |
306 switch (it->change_type()) { | |
307 case SyncChange::ACTION_ADD: | |
308 case SyncChange::ACTION_UPDATE: { | |
309 // Every setting we get from the server should have the acknowledged | |
310 // flag set. | |
311 DCHECK(managed_user_shared_setting.acknowledged()); | |
312 | |
313 if (has_key) { | |
314 // If the managed user already exists, it should be an update action. | |
315 DCHECK_EQ(SyncChange::ACTION_UPDATE, it->change_type()); | |
316 } else { | |
317 // Otherwise, it should be an add action. | |
318 DCHECK_EQ(SyncChange::ACTION_ADD, it->change_type()); | |
319 dict = new DictionaryValue; | |
320 update_dict->SetWithoutPathExpansion(key, dict); | |
321 } | |
322 scoped_ptr<Value> value( | |
323 base::JSONReader::Read(managed_user_shared_setting.value())); | |
324 dict->SetWithoutPathExpansion(kValue, value.release()); | |
325 dict->SetBooleanWithoutPathExpansion( | |
326 kAcknowledged, managed_user_shared_setting.acknowledged()); | |
327 break; | |
328 } | |
329 case SyncChange::ACTION_DELETE: { | |
330 if (has_key) | |
331 update_dict->RemoveWithoutPathExpansion(key, NULL); | |
332 else | |
333 NOTREACHED() << "Trying to delete nonexistent key " << key; | |
334 break; | |
335 } | |
336 case SyncChange::ACTION_INVALID: { | |
337 NOTREACHED(); | |
338 break; | |
339 } | |
340 } | |
341 callbacks_.Notify(mu_id, key); | |
342 } | |
343 | |
344 SyncError error; | |
345 return error; | |
346 } | |
OLD | NEW |