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/id_mapping_helper.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/memory/scoped_vector.h"
9#include "base/rand_util.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h"
13#include "chrome/browser/profiles/profile.h"
14#include "components/crx_file/id_util.h"
15#include "components/sync_driver/device_info.h"
16
17using base::DictionaryValue;
18using base::Value;
19using sync_driver::DeviceInfo;
20
21namespace extensions {
22
23std::string GetPublicIdFromGUID(
24    const base::DictionaryValue& id_mapping,
25    const std::string& guid) {
26  for (base::DictionaryValue::Iterator it(id_mapping);
27       !it.IsAtEnd();
28       it.Advance()) {
29    const base::Value& value = it.value();
30    std::string guid_in_value;
31    if (!value.GetAsString(&guid_in_value)) {
32      LOG(ERROR) << "Badly formatted dictionary";
33      continue;
34    }
35    if (guid_in_value == guid) {
36      return it.key();
37    }
38  }
39
40  return std::string();
41}
42
43std::string GetGUIDFromPublicId(
44    const base::DictionaryValue& id_mapping,
45    const std::string& id) {
46  std::string guid;
47  id_mapping.GetString(id, &guid);
48  return guid;
49}
50
51// Finds out a random unused id. First finds a random id.
52// If the id is in use, increments the id until it finds an unused id.
53std::string GetRandomId(
54  const base::DictionaryValue& mapping,
55  int device_count) {
56  // Set the max value for rand to be twice the device count.
57  int max = device_count * 2;
58  int rand_value = base::RandInt(0, max);
59  std::string string_value;
60  const base::Value *out_value;
61
62  do {
63    string_value = base::IntToString(rand_value);
64    rand_value++;
65  } while (mapping.Get(string_value, &out_value));
66
67  return string_value;
68}
69
70void CreateMappingForUnmappedDevices(
71    std::vector<DeviceInfo*>* device_info,
72    base::DictionaryValue* value) {
73  for (unsigned int i = 0; i < device_info->size(); ++i) {
74    DeviceInfo* device = (*device_info)[i];
75    std::string local_id = GetPublicIdFromGUID(*value,
76                                               device->guid());
77
78    // If the device does not have a local id, set one.
79    if (local_id.empty()) {
80      local_id = GetRandomId(*value, device_info->size());
81      value->SetString(local_id, device->guid());
82    }
83    device->set_public_id(local_id);
84  }
85}
86
87scoped_ptr<DeviceInfo> GetDeviceInfoForClientId(
88    const std::string& client_id,
89    const std::string& extension_id,
90    Profile* profile) {
91  DCHECK(crx_file::id_util::IdIsValid(extension_id)) << extension_id
92                                                     << " is not valid";
93  ScopedVector<DeviceInfo> devices = GetAllSignedInDevices(extension_id,
94                                                           profile);
95  for (ScopedVector<DeviceInfo>::iterator it = devices.begin();
96       it != devices.end();
97       ++it) {
98    if ((*it)->guid() == client_id) {
99      scoped_ptr<DeviceInfo> device(*it);
100      devices.weak_erase(it);
101      return device.Pass();
102    }
103  }
104  return scoped_ptr<DeviceInfo>();
105}
106
107}  // namespace  extensions
108