OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/cryptauth/cryptauth_device_manager.h" | 5 #include "components/cryptauth/cryptauth_device_manager.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 #include <stdexcept> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/base64url.h" | 11 #include "base/base64url.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
| 13 #include "base/strings/string_number_conversions.h" |
13 #include "components/cryptauth/cryptauth_client.h" | 14 #include "components/cryptauth/cryptauth_client.h" |
14 #include "components/cryptauth/pref_names.h" | 15 #include "components/cryptauth/pref_names.h" |
15 #include "components/cryptauth/sync_scheduler_impl.h" | 16 #include "components/cryptauth/sync_scheduler_impl.h" |
16 #include "components/prefs/pref_registry_simple.h" | 17 #include "components/prefs/pref_registry_simple.h" |
17 #include "components/prefs/pref_service.h" | 18 #include "components/prefs/pref_service.h" |
18 #include "components/prefs/scoped_user_pref_update.h" | 19 #include "components/prefs/scoped_user_pref_update.h" |
19 #include "components/proximity_auth/logging/logging.h" | 20 #include "components/proximity_auth/logging/logging.h" |
20 | 21 |
21 namespace cryptauth { | 22 namespace cryptauth { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 // The normal period between successful syncs, in hours. | 26 // The normal period between successful syncs, in hours. |
26 const int kRefreshPeriodHours = 24; | 27 const int kRefreshPeriodHours = 24; |
27 | 28 |
28 // A more aggressive period between sync attempts to recover when the last | 29 // A more aggressive period between sync attempts to recover when the last |
29 // sync attempt fails, in minutes. This is a base time that increases for each | 30 // sync attempt fails, in minutes. This is a base time that increases for each |
30 // subsequent failure. | 31 // subsequent failure. |
31 const int kDeviceSyncBaseRecoveryPeriodMinutes = 10; | 32 const int kDeviceSyncBaseRecoveryPeriodMinutes = 10; |
32 | 33 |
33 // The bound on the amount to jitter the period between syncs. | 34 // The bound on the amount to jitter the period between syncs. |
34 const double kDeviceSyncMaxJitterRatio = 0.2; | 35 const double kDeviceSyncMaxJitterRatio = 0.2; |
35 | 36 |
36 // Keys for ExternalDeviceInfo dictionaries that are stored in the user's prefs. | 37 // Keys for ExternalDeviceInfo dictionaries that are stored in the user's prefs. |
37 const char kExternalDeviceKeyPublicKey[] = "public_key"; | 38 const char kExternalDeviceKeyPublicKey[] = "public_key"; |
38 const char kExternalDeviceKeyDeviceName[] = "device_name"; | 39 const char kExternalDeviceKeyDeviceName[] = "device_name"; |
39 const char kExternalDeviceKeyBluetoothAddress[] = "bluetooth_address"; | 40 const char kExternalDeviceKeyBluetoothAddress[] = "bluetooth_address"; |
| 41 const char kExternalDeviceKeyUnlockKey[] = "unlock_key"; |
| 42 const char kExternalDeviceKeyUnlockable[] = "unlockable"; |
| 43 const char kExternalDeviceKeyLastUpdateTimeMillis[] = "last_update_time_millis"; |
| 44 const char kExternalDeviceKeyMobileHotspotSupported[] = |
| 45 "mobile_hotspot_supported"; |
| 46 const char kExternalDeviceKeyDeviceType[] = "device_type"; |
| 47 const char kExternalDeviceKeyBeaconSeeds[] = "beacon_seeds"; |
| 48 const char kExternalDeviceKeyBeaconSeedData[] = "beacon_seed_data"; |
| 49 const char kExternalDeviceKeyBeaconSeedStartMs[] = "beacon_seed_start_ms"; |
| 50 const char kExternalDeviceKeyBeaconSeedEndMs[] = "beacon_seed_end_ms"; |
| 51 |
| 52 // Converts BeaconSeed protos to a list value that can be stored in user prefs. |
| 53 std::unique_ptr<base::ListValue> BeaconSeedsToListValue( |
| 54 const google::protobuf::RepeatedPtrField<cryptauth::BeaconSeed>& seeds) { |
| 55 std::unique_ptr<base::ListValue> list(new base::ListValue()); |
| 56 |
| 57 for (int i = 0; i < seeds.size(); i++) { |
| 58 cryptauth::BeaconSeed seed = seeds.Get(i); |
| 59 |
| 60 if (!seed.has_data() |
| 61 || !seed.has_start_time_millis() |
| 62 || !seed.has_end_time_millis()) { |
| 63 PA_LOG(WARNING) << "Unable to serialize BeaconSeed due to missing data; " |
| 64 << "skipping."; |
| 65 continue; |
| 66 } |
| 67 |
| 68 std::unique_ptr<base::DictionaryValue> beacon_seed_value( |
| 69 new base::DictionaryValue()); |
| 70 |
| 71 // Note: Seed data is already base-64 encoded, so there is no need to |
| 72 // convert it. |
| 73 beacon_seed_value->SetString(kExternalDeviceKeyBeaconSeedData, seed.data()); |
| 74 |
| 75 // Set the timestamps as string representations of their numeric value |
| 76 // since there is no notion of a base::LongValue. |
| 77 beacon_seed_value->SetString( |
| 78 kExternalDeviceKeyBeaconSeedStartMs, |
| 79 std::to_string(seed.start_time_millis())); |
| 80 beacon_seed_value->SetString( |
| 81 kExternalDeviceKeyBeaconSeedEndMs, |
| 82 std::to_string(seed.end_time_millis())); |
| 83 |
| 84 list->Append(std::move(beacon_seed_value)); |
| 85 } |
| 86 |
| 87 return list; |
| 88 } |
40 | 89 |
41 // Converts an unlock key proto to a dictionary that can be stored in user | 90 // Converts an unlock key proto to a dictionary that can be stored in user |
42 // prefs. | 91 // prefs. |
43 std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary( | 92 std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary( |
44 const cryptauth::ExternalDeviceInfo& device) { | 93 const cryptauth::ExternalDeviceInfo& device) { |
| 94 // The device public key is a required value. |
| 95 if (!device.has_public_key()) { |
| 96 return nullptr; |
| 97 } |
| 98 |
45 std::unique_ptr<base::DictionaryValue> dictionary( | 99 std::unique_ptr<base::DictionaryValue> dictionary( |
46 new base::DictionaryValue()); | 100 new base::DictionaryValue()); |
47 | 101 |
48 // We store the device information in Base64Url form because dictionary values | 102 // Note that the device public key, name, and Bluetooth addresses are stored |
49 // must be valid UTF8 strings. | 103 // in Base64Url form because dictionary values must be valid UTF8 strings. |
50 std::string public_key_b64, device_name_b64, bluetooth_address_b64; | 104 |
| 105 std::string public_key_b64; |
51 base::Base64UrlEncode(device.public_key(), | 106 base::Base64UrlEncode(device.public_key(), |
52 base::Base64UrlEncodePolicy::INCLUDE_PADDING, | 107 base::Base64UrlEncodePolicy::INCLUDE_PADDING, |
53 &public_key_b64); | 108 &public_key_b64); |
54 base::Base64UrlEncode(device.friendly_device_name(), | 109 dictionary->SetString(kExternalDeviceKeyPublicKey, public_key_b64); |
55 base::Base64UrlEncodePolicy::INCLUDE_PADDING, | 110 |
56 &device_name_b64); | 111 if (device.has_friendly_device_name()) { |
57 base::Base64UrlEncode(device.bluetooth_address(), | 112 std::string device_name_b64; |
| 113 base::Base64UrlEncode(device.friendly_device_name(), |
| 114 base::Base64UrlEncodePolicy::INCLUDE_PADDING, |
| 115 &device_name_b64); |
| 116 dictionary->SetString(kExternalDeviceKeyDeviceName, device_name_b64); |
| 117 } |
| 118 |
| 119 if (device.has_bluetooth_address()) { |
| 120 std::string bluetooth_address_b64; |
| 121 base::Base64UrlEncode(device.bluetooth_address(), |
58 base::Base64UrlEncodePolicy::INCLUDE_PADDING, | 122 base::Base64UrlEncodePolicy::INCLUDE_PADDING, |
59 &bluetooth_address_b64); | 123 &bluetooth_address_b64); |
60 | 124 dictionary->SetString(kExternalDeviceKeyBluetoothAddress, |
61 dictionary->SetString(kExternalDeviceKeyPublicKey, public_key_b64); | 125 bluetooth_address_b64); |
62 dictionary->SetString(kExternalDeviceKeyDeviceName, device_name_b64); | 126 } |
63 dictionary->SetString(kExternalDeviceKeyBluetoothAddress, | 127 |
64 bluetooth_address_b64); | 128 if (device.has_unlock_key()) { |
| 129 dictionary->SetBoolean(kExternalDeviceKeyUnlockKey, |
| 130 device.unlock_key()); |
| 131 } |
| 132 |
| 133 if (device.has_unlockable()) { |
| 134 dictionary->SetBoolean(kExternalDeviceKeyUnlockable, |
| 135 device.unlockable()); |
| 136 } |
| 137 |
| 138 if (device.has_last_update_time_millis()) { |
| 139 dictionary->SetString(kExternalDeviceKeyLastUpdateTimeMillis, |
| 140 std::to_string(device.last_update_time_millis())); |
| 141 } |
| 142 |
| 143 if (device.has_mobile_hotspot_supported()) { |
| 144 dictionary->SetBoolean(kExternalDeviceKeyMobileHotspotSupported, |
| 145 device.mobile_hotspot_supported()); |
| 146 } |
| 147 |
| 148 if (device.has_device_type() && DeviceType_IsValid(device.device_type())) { |
| 149 dictionary->SetInteger(kExternalDeviceKeyDeviceType, |
| 150 device.device_type()); |
| 151 } |
| 152 |
| 153 std::unique_ptr<base::ListValue> beacon_seed_list = |
| 154 BeaconSeedsToListValue(device.beacon_seeds()); |
| 155 dictionary->Set(kExternalDeviceKeyBeaconSeeds, std::move(beacon_seed_list)); |
| 156 |
65 return dictionary; | 157 return dictionary; |
66 } | 158 } |
67 | 159 |
| 160 void AddBeaconSeedsToExternalDevice( |
| 161 const base::ListValue& beacon_seeds, |
| 162 cryptauth::ExternalDeviceInfo& external_device) { |
| 163 for (size_t i = 0; i < beacon_seeds.GetSize(); i++) { |
| 164 const base::DictionaryValue* seed_dictionary = nullptr; |
| 165 if (!beacon_seeds.GetDictionary(i, &seed_dictionary)) { |
| 166 PA_LOG(WARNING) << "Unable to retrieve BeaconSeed dictionary; " |
| 167 << "skipping."; |
| 168 continue; |
| 169 } |
| 170 |
| 171 std::string data, start_time_millis_str, end_time_millis_str; |
| 172 if (!seed_dictionary->GetString(kExternalDeviceKeyBeaconSeedData, &data) |
| 173 || !seed_dictionary->GetString( |
| 174 kExternalDeviceKeyBeaconSeedStartMs, |
| 175 &start_time_millis_str) |
| 176 || !seed_dictionary->GetString( |
| 177 kExternalDeviceKeyBeaconSeedEndMs, |
| 178 &end_time_millis_str)) { |
| 179 PA_LOG(WARNING) << "Unable to deserialize BeaconSeed due to missing " |
| 180 << "data; skipping."; |
| 181 continue; |
| 182 } |
| 183 |
| 184 int64_t start_time_millis, end_time_millis; |
| 185 if (!base::StringToInt64(start_time_millis_str, &start_time_millis) |
| 186 || !base::StringToInt64(end_time_millis_str, &end_time_millis)) { |
| 187 PA_LOG(WARNING) << "Unable to convert stored timestamp to int64_t: " |
| 188 << start_time_millis_str << " or " << end_time_millis_str; |
| 189 continue; |
| 190 } |
| 191 |
| 192 cryptauth::BeaconSeed* seed = external_device.add_beacon_seeds(); |
| 193 seed->set_data(data); |
| 194 seed->set_start_time_millis(start_time_millis); |
| 195 seed->set_end_time_millis(end_time_millis); |
| 196 } |
| 197 } |
| 198 |
68 // Converts an unlock key dictionary stored in user prefs to an | 199 // Converts an unlock key dictionary stored in user prefs to an |
69 // ExternalDeviceInfo proto. Returns true if the dictionary is valid, and the | 200 // ExternalDeviceInfo proto. Returns true if the dictionary is valid, and the |
70 // parsed proto is written to |external_device|. | 201 // parsed proto is written to |external_device|. |
71 bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary, | 202 bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary, |
72 cryptauth::ExternalDeviceInfo* external_device) { | 203 cryptauth::ExternalDeviceInfo* external_device) { |
73 std::string public_key_b64, device_name_b64, bluetooth_address_b64; | 204 std::string public_key_b64; |
74 if (!dictionary.GetString(kExternalDeviceKeyPublicKey, &public_key_b64) || | 205 if (!dictionary.GetString(kExternalDeviceKeyPublicKey, &public_key_b64)) { |
75 !dictionary.GetString(kExternalDeviceKeyDeviceName, &device_name_b64) || | 206 // The public key is a required field, so if it is absent, there is no |
76 !dictionary.GetString(kExternalDeviceKeyBluetoothAddress, | 207 // valid data to return. |
77 &bluetooth_address_b64)) { | |
78 return false; | 208 return false; |
79 } | 209 } |
80 | 210 |
81 // We store the device information in Base64Url form because dictionary values | 211 std::string public_key; |
82 // must be valid UTF8 strings. | |
83 std::string public_key, device_name, bluetooth_address; | |
84 if (!base::Base64UrlDecode(public_key_b64, | 212 if (!base::Base64UrlDecode(public_key_b64, |
85 base::Base64UrlDecodePolicy::REQUIRE_PADDING, | 213 base::Base64UrlDecodePolicy::REQUIRE_PADDING, |
86 &public_key) || | 214 &public_key)) { |
87 !base::Base64UrlDecode(device_name_b64, | 215 // The public key is stored as a Base64Url, so if it cannot be decoded, |
88 base::Base64UrlDecodePolicy::REQUIRE_PADDING, | 216 // there is no valid data to return. |
89 &device_name) || | |
90 !base::Base64UrlDecode(bluetooth_address_b64, | |
91 base::Base64UrlDecodePolicy::REQUIRE_PADDING, | |
92 &bluetooth_address)) { | |
93 return false; | 217 return false; |
94 } | 218 } |
95 | |
96 external_device->set_public_key(public_key); | 219 external_device->set_public_key(public_key); |
97 external_device->set_friendly_device_name(device_name); | 220 |
98 external_device->set_bluetooth_address(bluetooth_address); | 221 std::string device_name_b64; |
99 external_device->set_unlock_key(true); | 222 if (dictionary.GetString(kExternalDeviceKeyDeviceName, &device_name_b64)) { |
100 external_device->set_unlockable(false); | 223 std::string device_name; |
| 224 if (base::Base64UrlDecode(device_name_b64, |
| 225 base::Base64UrlDecodePolicy::REQUIRE_PADDING, |
| 226 &device_name)) { |
| 227 external_device->set_friendly_device_name(device_name); |
| 228 } |
| 229 } |
| 230 |
| 231 std::string bluetooth_address_b64; |
| 232 if (dictionary.GetString( |
| 233 kExternalDeviceKeyBluetoothAddress, &bluetooth_address_b64)) { |
| 234 std::string bluetooth_address; |
| 235 if (base::Base64UrlDecode(bluetooth_address_b64, |
| 236 base::Base64UrlDecodePolicy::REQUIRE_PADDING, |
| 237 &bluetooth_address)) { |
| 238 external_device->set_bluetooth_address(bluetooth_address); |
| 239 } |
| 240 } |
| 241 |
| 242 bool unlock_key; |
| 243 if (dictionary.GetBoolean(kExternalDeviceKeyUnlockKey, &unlock_key)) { |
| 244 external_device->set_unlock_key(unlock_key); |
| 245 } |
| 246 |
| 247 bool unlockable; |
| 248 if (dictionary.GetBoolean(kExternalDeviceKeyUnlockable, &unlockable)) { |
| 249 external_device->set_unlockable(unlockable); |
| 250 } |
| 251 |
| 252 std::string last_update_time_millis_str; |
| 253 if (dictionary.GetString( |
| 254 kExternalDeviceKeyLastUpdateTimeMillis, &last_update_time_millis_str)) { |
| 255 int64_t last_update_time_millis; |
| 256 if (base::StringToInt64( |
| 257 last_update_time_millis_str, &last_update_time_millis)) { |
| 258 external_device->set_last_update_time_millis(last_update_time_millis); |
| 259 } else { |
| 260 PA_LOG(WARNING) << "Unable to convert stored update time to int64_t: " |
| 261 << last_update_time_millis_str; |
| 262 } |
| 263 } |
| 264 |
| 265 bool mobile_hotspot_supported; |
| 266 if (dictionary.GetBoolean( |
| 267 kExternalDeviceKeyMobileHotspotSupported, &mobile_hotspot_supported)) { |
| 268 external_device->set_mobile_hotspot_supported(mobile_hotspot_supported); |
| 269 } |
| 270 |
| 271 int device_type; |
| 272 if (dictionary.GetInteger(kExternalDeviceKeyDeviceType, &device_type)) { |
| 273 if (DeviceType_IsValid(device_type)) { |
| 274 external_device->set_device_type(static_cast<DeviceType>(device_type)); |
| 275 } |
| 276 } |
| 277 |
| 278 const base::ListValue* beacon_seeds = nullptr; |
| 279 dictionary.GetList(kExternalDeviceKeyBeaconSeeds, &beacon_seeds); |
| 280 if (beacon_seeds) { |
| 281 AddBeaconSeedsToExternalDevice(*beacon_seeds, *external_device); |
| 282 } |
| 283 |
101 return true; | 284 return true; |
102 } | 285 } |
103 | 286 |
104 } // namespace | 287 } // namespace |
105 | 288 |
106 CryptAuthDeviceManager::CryptAuthDeviceManager( | 289 CryptAuthDeviceManager::CryptAuthDeviceManager( |
107 std::unique_ptr<base::Clock> clock, | 290 std::unique_ptr<base::Clock> clock, |
108 std::unique_ptr<CryptAuthClientFactory> client_factory, | 291 std::unique_ptr<CryptAuthClientFactory> client_factory, |
109 CryptAuthGCMManager* gcm_manager, | 292 CryptAuthGCMManager* gcm_manager, |
110 PrefService* pref_service) | 293 PrefService* pref_service) |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 request.set_invocation_reason(invocation_reason); | 485 request.set_invocation_reason(invocation_reason); |
303 request.set_allow_stale_read(is_sync_speculative); | 486 request.set_allow_stale_read(is_sync_speculative); |
304 cryptauth_client_->GetMyDevices( | 487 cryptauth_client_->GetMyDevices( |
305 request, base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesSuccess, | 488 request, base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesSuccess, |
306 weak_ptr_factory_.GetWeakPtr()), | 489 weak_ptr_factory_.GetWeakPtr()), |
307 base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesFailure, | 490 base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesFailure, |
308 weak_ptr_factory_.GetWeakPtr())); | 491 weak_ptr_factory_.GetWeakPtr())); |
309 } | 492 } |
310 | 493 |
311 } // namespace cryptauth | 494 } // namespace cryptauth |
OLD | NEW |