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