1 // Copyright (c) 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/extensions/api/signed_in_devices/signed_in_devices_api.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/values.h"
11 #include "chrome/browser/extensions/api/signed_in_devices/id_mapping_helper.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/sync/device_info_sync_service_factory.h"
14 #include "chrome/common/extensions/api/signed_in_devices.h"
15 #include "components/sync_device_info/device_info_sync_service.h"
16 #include "components/sync_device_info/device_info_tracker.h"
17 #include "components/sync_device_info/local_device_info_provider.h"
18 #include "extensions/browser/extension_prefs.h"
19 
20 using base::DictionaryValue;
21 using syncer::DeviceInfo;
22 using syncer::DeviceInfoTracker;
23 using syncer::LocalDeviceInfoProvider;
24 
25 namespace extensions {
26 
27 static const char kPrefStringForIdMapping[] = "id_mapping_dictioanry";
28 
29 // Gets the dictionary that stores the id mapping. The dictionary is stored
30 // in the |ExtensionPrefs|.
GetIdMappingDictionary(ExtensionPrefs * extension_prefs,const std::string & extension_id)31 const base::DictionaryValue* GetIdMappingDictionary(
32     ExtensionPrefs* extension_prefs,
33     const std::string& extension_id) {
34   const base::DictionaryValue* out_value = NULL;
35   if (!extension_prefs->ReadPrefAsDictionary(
36           extension_id,
37           kPrefStringForIdMapping,
38           &out_value) || out_value == NULL) {
39     // Looks like this is the first call to get the dictionary. Let us create
40     // a dictionary and set it in to |extension_prefs|.
41     std::unique_ptr<base::DictionaryValue> dictionary(
42         new base::DictionaryValue());
43     out_value = dictionary.get();
44     extension_prefs->UpdateExtensionPref(extension_id, kPrefStringForIdMapping,
45                                          std::move(dictionary));
46   }
47 
48   return out_value;
49 }
50 
51 // Helper routine to get all signed in devices. The helper takes in
52 // the pointers for |DeviceInfoTracker| and |Extensionprefs|. This
53 // makes it easier to test by passing mock values for these pointers.
GetAllSignedInDevices(const std::string & extension_id,DeviceInfoTracker * device_tracker,ExtensionPrefs * extension_prefs)54 std::vector<std::unique_ptr<DeviceInfo>> GetAllSignedInDevices(
55     const std::string& extension_id,
56     DeviceInfoTracker* device_tracker,
57     ExtensionPrefs* extension_prefs) {
58   DCHECK(device_tracker);
59   std::vector<std::unique_ptr<DeviceInfo>> devices =
60       device_tracker->GetAllDeviceInfo();
61   const base::DictionaryValue* mapping_dictionary = GetIdMappingDictionary(
62       extension_prefs,
63       extension_id);
64 
65   CHECK(mapping_dictionary);
66 
67   // |mapping_dictionary| is const. So make an editable copy.
68   std::unique_ptr<base::DictionaryValue> editable_mapping_dictionary(
69       mapping_dictionary->DeepCopy());
70 
71   CreateMappingForUnmappedDevices(devices, editable_mapping_dictionary.get());
72 
73   // Write into |ExtensionPrefs| which will get persisted in disk.
74   extension_prefs->UpdateExtensionPref(extension_id, kPrefStringForIdMapping,
75                                        std::move(editable_mapping_dictionary));
76   return devices;
77 }
78 
GetAllSignedInDevices(const std::string & extension_id,Profile * profile)79 std::vector<std::unique_ptr<DeviceInfo>> GetAllSignedInDevices(
80     const std::string& extension_id,
81     Profile* profile) {
82   // Get the device tracker and extension prefs pointers
83   // and call the helper.
84   DeviceInfoTracker* device_tracker =
85       DeviceInfoSyncServiceFactory::GetForProfile(profile)
86           ->GetDeviceInfoTracker();
87   DCHECK(device_tracker);
88   if (!device_tracker->IsSyncing()) {
89     // Devices are not sync'ing.
90     return std::vector<std::unique_ptr<DeviceInfo>>();
91   }
92 
93   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile);
94 
95   return GetAllSignedInDevices(extension_id, device_tracker, extension_prefs);
96 }
97 
GetLocalDeviceInfo(const std::string & extension_id,Profile * profile)98 std::unique_ptr<DeviceInfo> GetLocalDeviceInfo(const std::string& extension_id,
99                                                Profile* profile) {
100   syncer::DeviceInfoSyncService* service =
101       DeviceInfoSyncServiceFactory::GetForProfile(profile);
102   if (!service) {
103     return nullptr;
104   }
105 
106   const LocalDeviceInfoProvider* local_device_info_provider =
107       service->GetLocalDeviceInfoProvider();
108   DCHECK(local_device_info_provider);
109   const DeviceInfo* local_device =
110       local_device_info_provider->GetLocalDeviceInfo();
111   if (!local_device)
112     return nullptr;
113 
114   // TODO(karandeepb): Can't we just return a copy of |local_device|, without
115   // having to look it up by GUID?
116   return GetDeviceInfoForClientId(local_device->guid(), extension_id, profile);
117 }
118 
Run()119 ExtensionFunction::ResponseAction SignedInDevicesGetFunction::Run() {
120   std::unique_ptr<api::signed_in_devices::Get::Params> params(
121       api::signed_in_devices::Get::Params::Create(*args_));
122   EXTENSION_FUNCTION_VALIDATE(params.get());
123 
124   bool is_local = params->is_local.get() ? *params->is_local : false;
125 
126   Profile* profile = Profile::FromBrowserContext(browser_context());
127   if (is_local) {
128     std::unique_ptr<DeviceInfo> device =
129         GetLocalDeviceInfo(extension_id(), profile);
130     std::unique_ptr<base::ListValue> result(new base::ListValue());
131     if (device.get()) {
132       result->Append(device->ToValue());
133     }
134     return RespondNow(
135         OneArgument(base::Value::FromUniquePtrValue(std::move(result))));
136   }
137 
138   std::vector<std::unique_ptr<DeviceInfo>> devices =
139       GetAllSignedInDevices(extension_id(), profile);
140 
141   std::unique_ptr<base::ListValue> result(new base::ListValue());
142 
143   for (const std::unique_ptr<DeviceInfo>& device : devices)
144     result->Append(device->ToValue());
145 
146   return RespondNow(
147       OneArgument(base::Value::FromUniquePtrValue(std::move(result))));
148 }
149 
150 }  // namespace extensions
151