- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / managed_mode / managed_user_sync_service.cc
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_sync_service.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/pref_names.h"
15 #include "components/user_prefs/pref_registry_syncable.h"
16 #include "sync/api/sync_change.h"
17 #include "sync/api/sync_data.h"
18 #include "sync/api/sync_error.h"
19 #include "sync/api/sync_error_factory.h"
20 #include "sync/api/sync_merge_result.h"
21 #include "sync/protocol/sync.pb.h"
22
23 using base::DictionaryValue;
24 using user_prefs::PrefRegistrySyncable;
25 using syncer::MANAGED_USERS;
26 using syncer::ModelType;
27 using syncer::SyncChange;
28 using syncer::SyncChangeList;
29 using syncer::SyncChangeProcessor;
30 using syncer::SyncData;
31 using syncer::SyncDataList;
32 using syncer::SyncError;
33 using syncer::SyncErrorFactory;
34 using syncer::SyncMergeResult;
35 using sync_pb::ManagedUserSpecifics;
36
37 namespace {
38
39 #if defined(OS_CHROMEOS)
40 const char kChromeOSAvatarPrefix[] = "chromeos-avatar-index:";
41 #else
42 const char kChromeAvatarPrefix[] = "chrome-avatar-index:";
43 #endif
44
45 SyncData CreateLocalSyncData(const std::string& id,
46                              const std::string& name,
47                              bool acknowledged,
48                              const std::string& master_key,
49                              const std::string& chrome_avatar,
50                              const std::string& chromeos_avatar) {
51   ::sync_pb::EntitySpecifics specifics;
52   specifics.mutable_managed_user()->set_id(id);
53   specifics.mutable_managed_user()->set_name(name);
54   if (!chrome_avatar.empty())
55     specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
56   else
57     specifics.mutable_managed_user()->clear_chrome_avatar();
58   if (!chromeos_avatar.empty())
59     specifics.mutable_managed_user()->set_chromeos_avatar(chromeos_avatar);
60   if (!master_key.empty())
61     specifics.mutable_managed_user()->set_master_key(master_key);
62   if (acknowledged)
63     specifics.mutable_managed_user()->set_acknowledged(true);
64   return SyncData::CreateLocalData(id, name, specifics);
65 }
66
67 SyncData CreateSyncDataFromDictionaryEntry(
68     const DictionaryValue::Iterator& it) {
69   const DictionaryValue* dict = NULL;
70   bool success = it.value().GetAsDictionary(&dict);
71   DCHECK(success);
72   bool acknowledged = false;
73   dict->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
74   std::string name;
75   dict->GetString(ManagedUserSyncService::kName, &name);
76   DCHECK(!name.empty());
77   std::string master_key;
78   dict->GetString(ManagedUserSyncService::kMasterKey, &master_key);
79   std::string chrome_avatar;
80   dict->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
81   std::string chromeos_avatar;
82   dict->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
83
84   return CreateLocalSyncData(it.key(), name, acknowledged, master_key,
85                              chrome_avatar, chromeos_avatar);
86 }
87
88 }  // namespace
89
90 const char ManagedUserSyncService::kAcknowledged[] = "acknowledged";
91 const char ManagedUserSyncService::kChromeAvatar[] = "chromeAvatar";
92 const char ManagedUserSyncService::kChromeOsAvatar[] = "chromeOsAvatar";
93 const char ManagedUserSyncService::kMasterKey[] = "masterKey";
94 const char ManagedUserSyncService::kName[] = "name";
95 const int ManagedUserSyncService::kNoAvatar = -100;
96
97 ManagedUserSyncService::ManagedUserSyncService(PrefService* prefs)
98     : prefs_(prefs) {
99   pref_change_registrar_.Init(prefs_);
100   pref_change_registrar_.Add(
101       prefs::kGoogleServicesLastUsername,
102       base::Bind(&ManagedUserSyncService::OnLastSignedInUsernameChange,
103                  base::Unretained(this)));
104 }
105
106 ManagedUserSyncService::~ManagedUserSyncService() {
107 }
108
109 // static
110 void ManagedUserSyncService::RegisterProfilePrefs(
111     PrefRegistrySyncable* registry) {
112   registry->RegisterDictionaryPref(prefs::kManagedUsers,
113                                    PrefRegistrySyncable::UNSYNCABLE_PREF);
114 }
115
116 // static
117 bool ManagedUserSyncService::GetAvatarIndex(const std::string& avatar_str,
118                                             int* avatar_index) {
119   // TODO(ibraaaa): when chrome OS supports supervised users avatar syncing
120   // then update this method to support extracting the avatar index
121   // for chrome OS as well.
122   DCHECK(avatar_index);
123   if (avatar_str.empty()) {
124     *avatar_index = kNoAvatar;
125     return true;
126   }
127 #if defined(OS_CHROMEOS)
128   const char* prefix = kChromeOSAvatarPrefix;
129 #else
130   const char* prefix = kChromeAvatarPrefix;
131 #endif
132   size_t prefix_len = strlen(prefix);
133   if (avatar_str.size() <= prefix_len ||
134       avatar_str.substr(0, prefix_len) != prefix) {
135     return false;
136   }
137
138   return base::StringToInt(avatar_str.substr(prefix_len), avatar_index);
139 }
140
141 // static
142 std::string ManagedUserSyncService::BuildAvatarString(int avatar_index) {
143 #if defined(OS_CHROMEOS)
144   const char* prefix = kChromeOSAvatarPrefix;
145 #else
146   const char* prefix = kChromeAvatarPrefix;
147 #endif
148   return base::StringPrintf("%s%d", prefix, avatar_index);
149 }
150
151 void ManagedUserSyncService::AddObserver(
152     ManagedUserSyncServiceObserver* observer) {
153   observers_.AddObserver(observer);
154 }
155
156 void ManagedUserSyncService::RemoveObserver(
157     ManagedUserSyncServiceObserver* observer) {
158   observers_.RemoveObserver(observer);
159 }
160
161 void ManagedUserSyncService::AddManagedUser(const std::string& id,
162                                             const std::string& name,
163                                             const std::string& master_key,
164                                             int avatar_index) {
165   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
166   DictionaryValue* dict = update.Get();
167   DictionaryValue* value = new DictionaryValue;
168   value->SetString(kName, name);
169   value->SetString(kMasterKey, master_key);
170   std::string chrome_avatar;
171   std::string chromeos_avatar;
172 #if defined(OS_CHROMEOS)
173   chromeos_avatar = BuildAvatarString(avatar_index);
174 #else
175   chrome_avatar = BuildAvatarString(avatar_index);
176 #endif
177   value->SetString(kChromeAvatar, chrome_avatar);
178   value->SetString(kChromeOsAvatar, chromeos_avatar);
179   DCHECK(!dict->HasKey(id));
180   dict->SetWithoutPathExpansion(id, value);
181
182   if (!sync_processor_)
183     return;
184
185   // If we're already syncing, create a new change and upload it.
186   SyncChangeList change_list;
187   change_list.push_back(SyncChange(
188       FROM_HERE,
189       SyncChange::ACTION_ADD,
190       CreateLocalSyncData(id, name, false, master_key,
191                           chrome_avatar, chromeos_avatar)));
192   SyncError error =
193       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
194   DCHECK(!error.IsSet()) << error.ToString();
195 }
196
197 void ManagedUserSyncService::DeleteManagedUser(const std::string& id) {
198   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
199   bool success = update->RemoveWithoutPathExpansion(id, NULL);
200   DCHECK(success);
201
202   if (!sync_processor_)
203     return;
204
205   SyncChangeList change_list;
206   change_list.push_back(SyncChange(
207       FROM_HERE,
208       SyncChange::ACTION_DELETE,
209       SyncData::CreateLocalDelete(id, MANAGED_USERS)));
210   SyncError sync_error =
211       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
212   DCHECK(!sync_error.IsSet());
213 }
214
215 const DictionaryValue* ManagedUserSyncService::GetManagedUsers() {
216   DCHECK(sync_processor_);
217   return prefs_->GetDictionary(prefs::kManagedUsers);
218 }
219
220 bool ManagedUserSyncService::UpdateManagedUserAvatarIfNeeded(
221     const std::string& id,
222     int avatar_index) {
223   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
224   DictionaryValue* dict = update.Get();
225   DCHECK(dict->HasKey(id));
226   DictionaryValue* value = NULL;
227   bool success = dict->GetDictionaryWithoutPathExpansion(id, &value);
228   DCHECK(success);
229
230   bool acknowledged = false;
231   value->GetBoolean(ManagedUserSyncService::kAcknowledged, &acknowledged);
232   std::string name;
233   value->GetString(ManagedUserSyncService::kName, &name);
234   std::string master_key;
235   value->GetString(ManagedUserSyncService::kMasterKey, &master_key);
236   // TODO(ibraaaa): this should be updated when avatar syncing for
237   // supervised users is implemented on Chrome OS.
238   std::string chromeos_avatar;
239   value->GetString(ManagedUserSyncService::kChromeOsAvatar, &chromeos_avatar);
240   std::string chrome_avatar;
241   value->GetString(ManagedUserSyncService::kChromeAvatar, &chrome_avatar);
242   if (!chrome_avatar.empty() && avatar_index != kNoAvatar)
243     return false;
244
245   chrome_avatar = avatar_index == kNoAvatar ?
246       std::string() : BuildAvatarString(avatar_index);
247   value->SetString(kChromeAvatar, chrome_avatar);
248
249   if (!sync_processor_)
250     return true;
251
252   SyncChangeList change_list;
253   change_list.push_back(SyncChange(
254       FROM_HERE,
255       SyncChange::ACTION_UPDATE,
256       CreateLocalSyncData(id, name, acknowledged, master_key,
257                           chrome_avatar, chromeos_avatar)));
258   SyncError error =
259       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
260   DCHECK(!error.IsSet()) << error.ToString();
261   return true;
262 }
263
264 void ManagedUserSyncService::ClearManagedUserAvatar(const std::string& id) {
265   bool cleared = UpdateManagedUserAvatarIfNeeded(id, kNoAvatar);
266   DCHECK(cleared);
267 }
268
269 void ManagedUserSyncService::GetManagedUsersAsync(
270     const ManagedUsersCallback& callback) {
271   // If we are already syncing, just run the callback.
272   if (sync_processor_) {
273     callback.Run(GetManagedUsers());
274     return;
275   }
276
277   // Otherwise queue it up until we start syncing.
278   callbacks_.push_back(callback);
279 }
280
281 void ManagedUserSyncService::Shutdown() {
282   NotifyManagedUsersSyncingStopped();
283 }
284
285 SyncMergeResult ManagedUserSyncService::MergeDataAndStartSyncing(
286     ModelType type,
287     const SyncDataList& initial_sync_data,
288     scoped_ptr<SyncChangeProcessor> sync_processor,
289     scoped_ptr<SyncErrorFactory> error_handler) {
290   DCHECK_EQ(MANAGED_USERS, type);
291   sync_processor_ = sync_processor.Pass();
292   error_handler_ = error_handler.Pass();
293
294   SyncChangeList change_list;
295   SyncMergeResult result(MANAGED_USERS);
296
297   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
298   DictionaryValue* dict = update.Get();
299   result.set_num_items_before_association(dict->size());
300   std::set<std::string> seen_ids;
301   int num_items_added = 0;
302   int num_items_modified = 0;
303   for (SyncDataList::const_iterator it = initial_sync_data.begin();
304        it != initial_sync_data.end(); ++it) {
305     DCHECK_EQ(MANAGED_USERS, it->GetDataType());
306     const ManagedUserSpecifics& managed_user =
307         it->GetSpecifics().managed_user();
308     DictionaryValue* value = new DictionaryValue();
309     value->SetString(kName, managed_user.name());
310     value->SetBoolean(kAcknowledged, managed_user.acknowledged());
311     value->SetString(kMasterKey, managed_user.master_key());
312     value->SetString(kChromeAvatar, managed_user.chrome_avatar());
313     value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
314     if (dict->HasKey(managed_user.id()))
315       num_items_modified++;
316     else
317       num_items_added++;
318     dict->SetWithoutPathExpansion(managed_user.id(), value);
319     seen_ids.insert(managed_user.id());
320   }
321
322   for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
323     if (seen_ids.find(it.key()) != seen_ids.end())
324       continue;
325
326     change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD,
327                                      CreateSyncDataFromDictionaryEntry(it)));
328   }
329   result.set_error(sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
330
331   result.set_num_items_modified(num_items_modified);
332   result.set_num_items_added(num_items_added);
333   result.set_num_items_after_association(dict->size());
334
335   DispatchCallbacks();
336
337   return result;
338 }
339
340 void ManagedUserSyncService::StopSyncing(ModelType type) {
341   DCHECK_EQ(MANAGED_USERS, type);
342   // The observers may want to change the Sync data, so notify them before
343   // resetting the |sync_processor_|.
344   NotifyManagedUsersSyncingStopped();
345   sync_processor_.reset();
346   error_handler_.reset();
347 }
348
349 SyncDataList ManagedUserSyncService::GetAllSyncData(
350     ModelType type) const {
351   SyncDataList data;
352   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
353   DictionaryValue* dict = update.Get();
354   for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance())
355     data.push_back(CreateSyncDataFromDictionaryEntry(it));
356
357   return data;
358 }
359
360 SyncError ManagedUserSyncService::ProcessSyncChanges(
361     const tracked_objects::Location& from_here,
362     const SyncChangeList& change_list) {
363   SyncError error;
364   DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
365   DictionaryValue* dict = update.Get();
366   for (SyncChangeList::const_iterator it = change_list.begin();
367        it != change_list.end(); ++it) {
368     SyncData data = it->sync_data();
369     DCHECK_EQ(MANAGED_USERS, data.GetDataType());
370     const ManagedUserSpecifics& managed_user =
371         data.GetSpecifics().managed_user();
372     switch (it->change_type()) {
373       case SyncChange::ACTION_ADD:
374       case SyncChange::ACTION_UPDATE: {
375         // Every item we get from the server should be acknowledged.
376         DCHECK(managed_user.acknowledged());
377         const DictionaryValue* old_value = NULL;
378         dict->GetDictionaryWithoutPathExpansion(managed_user.id(), &old_value);
379
380         // For an update action, the managed user should already exist, for an
381         // add action, it should not.
382         DCHECK_EQ(
383             old_value ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD,
384             it->change_type());
385
386         // If the managed user switched from unacknowledged to acknowledged,
387         // we might need to continue with a registration.
388         if (old_value && !old_value->HasKey(kAcknowledged))
389           NotifyManagedUserAcknowledged(managed_user.id());
390
391         DictionaryValue* value = new DictionaryValue;
392         value->SetString(kName, managed_user.name());
393         value->SetBoolean(kAcknowledged, managed_user.acknowledged());
394         value->SetString(kMasterKey, managed_user.master_key());
395         value->SetString(kChromeAvatar, managed_user.chrome_avatar());
396         value->SetString(kChromeOsAvatar, managed_user.chromeos_avatar());
397         dict->SetWithoutPathExpansion(managed_user.id(), value);
398         break;
399       }
400       case SyncChange::ACTION_DELETE: {
401         DCHECK(dict->HasKey(managed_user.id())) << managed_user.id();
402         dict->RemoveWithoutPathExpansion(managed_user.id(), NULL);
403         break;
404       }
405       case SyncChange::ACTION_INVALID: {
406         NOTREACHED();
407         break;
408       }
409     }
410   }
411   return error;
412 }
413
414 void ManagedUserSyncService::OnLastSignedInUsernameChange() {
415   DCHECK(!sync_processor_);
416
417   // If the last signed in user changes, we clear all data, to avoid managed
418   // users from one custodian appearing in another one's profile.
419   prefs_->ClearPref(prefs::kManagedUsers);
420 }
421
422 void ManagedUserSyncService::NotifyManagedUserAcknowledged(
423     const std::string& managed_user_id) {
424   FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
425                     OnManagedUserAcknowledged(managed_user_id));
426 }
427
428 void ManagedUserSyncService::NotifyManagedUsersSyncingStopped() {
429   FOR_EACH_OBSERVER(ManagedUserSyncServiceObserver, observers_,
430                     OnManagedUsersSyncingStopped());
431 }
432
433 void ManagedUserSyncService::DispatchCallbacks() {
434   const DictionaryValue* managed_users =
435       prefs_->GetDictionary(prefs::kManagedUsers);
436   for (std::vector<ManagedUsersCallback>::iterator it = callbacks_.begin();
437        it != callbacks_.end(); ++it) {
438     it->Run(managed_users);
439   }
440   callbacks_.clear();
441 }