Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: components/proximity_auth/cryptauth/cryptauth_device_manager.cc

Issue 2502343003: Moved //components/proximity_auth/cryptauth to //components/cryptauth. (Closed)
Patch Set: Fixed proto #includes. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "components/proximity_auth/cryptauth/cryptauth_device_manager.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/base64url.h"
12 #include "base/memory/ptr_util.h"
13 #include "components/prefs/pref_registry_simple.h"
14 #include "components/prefs/pref_service.h"
15 #include "components/prefs/scoped_user_pref_update.h"
16 #include "components/proximity_auth/cryptauth/cryptauth_client.h"
17 #include "components/proximity_auth/cryptauth/pref_names.h"
18 #include "components/proximity_auth/cryptauth/sync_scheduler_impl.h"
19 #include "components/proximity_auth/logging/logging.h"
20
21 namespace proximity_auth {
22
23 namespace {
24
25 // The normal period between successful syncs, in hours.
26 const int kRefreshPeriodHours = 24;
27
28 // 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 // subsequent failure.
31 const int kDeviceSyncBaseRecoveryPeriodMinutes = 10;
32
33 // The bound on the amount to jitter the period between syncs.
34 const double kDeviceSyncMaxJitterRatio = 0.2;
35
36 // Keys for ExternalDeviceInfo dictionaries that are stored in the user's prefs.
37 const char kExternalDeviceKeyPublicKey[] = "public_key";
38 const char kExternalDeviceKeyDeviceName[] = "device_name";
39 const char kExternalDeviceKeyBluetoothAddress[] = "bluetooth_address";
40
41 // Converts an unlock key proto to a dictionary that can be stored in user
42 // prefs.
43 std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary(
44 const cryptauth::ExternalDeviceInfo& device) {
45 std::unique_ptr<base::DictionaryValue> dictionary(
46 new base::DictionaryValue());
47
48 // We store the device information in Base64Url form because dictionary values
49 // must be valid UTF8 strings.
50 std::string public_key_b64, device_name_b64, bluetooth_address_b64;
51 base::Base64UrlEncode(device.public_key(),
52 base::Base64UrlEncodePolicy::INCLUDE_PADDING,
53 &public_key_b64);
54 base::Base64UrlEncode(device.friendly_device_name(),
55 base::Base64UrlEncodePolicy::INCLUDE_PADDING,
56 &device_name_b64);
57 base::Base64UrlEncode(device.bluetooth_address(),
58 base::Base64UrlEncodePolicy::INCLUDE_PADDING,
59 &bluetooth_address_b64);
60
61 dictionary->SetString(kExternalDeviceKeyPublicKey, public_key_b64);
62 dictionary->SetString(kExternalDeviceKeyDeviceName, device_name_b64);
63 dictionary->SetString(kExternalDeviceKeyBluetoothAddress,
64 bluetooth_address_b64);
65 return dictionary;
66 }
67
68 // Converts an unlock key dictionary stored in user prefs to an
69 // ExternalDeviceInfo proto. Returns true if the dictionary is valid, and the
70 // parsed proto is written to |external_device|.
71 bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary,
72 cryptauth::ExternalDeviceInfo* external_device) {
73 std::string public_key_b64, device_name_b64, bluetooth_address_b64;
74 if (!dictionary.GetString(kExternalDeviceKeyPublicKey, &public_key_b64) ||
75 !dictionary.GetString(kExternalDeviceKeyDeviceName, &device_name_b64) ||
76 !dictionary.GetString(kExternalDeviceKeyBluetoothAddress,
77 &bluetooth_address_b64)) {
78 return false;
79 }
80
81 // We store the device information in Base64Url form because dictionary values
82 // must be valid UTF8 strings.
83 std::string public_key, device_name, bluetooth_address;
84 if (!base::Base64UrlDecode(public_key_b64,
85 base::Base64UrlDecodePolicy::REQUIRE_PADDING,
86 &public_key) ||
87 !base::Base64UrlDecode(device_name_b64,
88 base::Base64UrlDecodePolicy::REQUIRE_PADDING,
89 &device_name) ||
90 !base::Base64UrlDecode(bluetooth_address_b64,
91 base::Base64UrlDecodePolicy::REQUIRE_PADDING,
92 &bluetooth_address)) {
93 return false;
94 }
95
96 external_device->set_public_key(public_key);
97 external_device->set_friendly_device_name(device_name);
98 external_device->set_bluetooth_address(bluetooth_address);
99 external_device->set_unlock_key(true);
100 external_device->set_unlockable(false);
101 return true;
102 }
103
104 } // namespace
105
106 CryptAuthDeviceManager::CryptAuthDeviceManager(
107 std::unique_ptr<base::Clock> clock,
108 std::unique_ptr<CryptAuthClientFactory> client_factory,
109 CryptAuthGCMManager* gcm_manager,
110 PrefService* pref_service)
111 : clock_(std::move(clock)),
112 client_factory_(std::move(client_factory)),
113 gcm_manager_(gcm_manager),
114 pref_service_(pref_service),
115 weak_ptr_factory_(this) {
116 UpdateUnlockKeysFromPrefs();
117 }
118
119 CryptAuthDeviceManager::~CryptAuthDeviceManager() {
120 gcm_manager_->RemoveObserver(this);
121 }
122
123 // static
124 void CryptAuthDeviceManager::RegisterPrefs(PrefRegistrySimple* registry) {
125 registry->RegisterDoublePref(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
126 0.0);
127 registry->RegisterBooleanPref(
128 prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure, false);
129 registry->RegisterIntegerPref(prefs::kCryptAuthDeviceSyncReason,
130 cryptauth::INVOCATION_REASON_UNKNOWN);
131 registry->RegisterListPref(prefs::kCryptAuthDeviceSyncUnlockKeys);
132 }
133
134 void CryptAuthDeviceManager::Start() {
135 gcm_manager_->AddObserver(this);
136
137 base::Time last_successful_sync = GetLastSyncTime();
138 base::TimeDelta elapsed_time_since_last_sync =
139 clock_->Now() - last_successful_sync;
140
141 bool is_recovering_from_failure =
142 pref_service_->GetBoolean(
143 prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure) ||
144 last_successful_sync.is_null();
145
146 scheduler_ = CreateSyncScheduler();
147 scheduler_->Start(elapsed_time_since_last_sync,
148 is_recovering_from_failure
149 ? SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
150 : SyncScheduler::Strategy::PERIODIC_REFRESH);
151 }
152
153 void CryptAuthDeviceManager::AddObserver(Observer* observer) {
154 observers_.AddObserver(observer);
155 }
156
157 void CryptAuthDeviceManager::RemoveObserver(Observer* observer) {
158 observers_.RemoveObserver(observer);
159 }
160
161 void CryptAuthDeviceManager::ForceSyncNow(
162 cryptauth::InvocationReason invocation_reason) {
163 pref_service_->SetInteger(prefs::kCryptAuthDeviceSyncReason,
164 invocation_reason);
165 scheduler_->ForceSync();
166 }
167
168 base::Time CryptAuthDeviceManager::GetLastSyncTime() const {
169 return base::Time::FromDoubleT(
170 pref_service_->GetDouble(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds));
171 }
172
173 base::TimeDelta CryptAuthDeviceManager::GetTimeToNextAttempt() const {
174 return scheduler_->GetTimeToNextSync();
175 }
176
177 bool CryptAuthDeviceManager::IsSyncInProgress() const {
178 return scheduler_->GetSyncState() ==
179 SyncScheduler::SyncState::SYNC_IN_PROGRESS;
180 }
181
182 bool CryptAuthDeviceManager::IsRecoveringFromFailure() const {
183 return scheduler_->GetStrategy() ==
184 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY;
185 }
186
187 void CryptAuthDeviceManager::OnGetMyDevicesSuccess(
188 const cryptauth::GetMyDevicesResponse& response) {
189 // Update the unlock keys stored in the user's prefs.
190 std::unique_ptr<base::ListValue> unlock_keys_pref(new base::ListValue());
191 std::unique_ptr<base::ListValue> devices_as_list(new base::ListValue());
192 for (const auto& device : response.devices()) {
193 devices_as_list->Append(UnlockKeyToDictionary(device));
194 if (device.unlock_key())
195 unlock_keys_pref->Append(UnlockKeyToDictionary(device));
196 }
197 PA_LOG(INFO) << "Devices Synced:\n" << *devices_as_list;
198
199 bool unlock_keys_changed = !unlock_keys_pref->Equals(
200 pref_service_->GetList(prefs::kCryptAuthDeviceSyncUnlockKeys));
201 {
202 ListPrefUpdate update(pref_service_, prefs::kCryptAuthDeviceSyncUnlockKeys);
203 update.Get()->Swap(unlock_keys_pref.get());
204 }
205 UpdateUnlockKeysFromPrefs();
206
207 // Reset metadata used for scheduling syncing.
208 pref_service_->SetBoolean(prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure,
209 false);
210 pref_service_->SetDouble(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
211 clock_->Now().ToDoubleT());
212 pref_service_->SetInteger(prefs::kCryptAuthDeviceSyncReason,
213 cryptauth::INVOCATION_REASON_UNKNOWN);
214
215 sync_request_->OnDidComplete(true);
216 cryptauth_client_.reset();
217 sync_request_.reset();
218 for (auto& observer : observers_) {
219 observer.OnSyncFinished(SyncResult::SUCCESS,
220 unlock_keys_changed
221 ? DeviceChangeResult::CHANGED
222 : DeviceChangeResult::UNCHANGED);
223 }
224 }
225
226 void CryptAuthDeviceManager::OnGetMyDevicesFailure(const std::string& error) {
227 PA_LOG(ERROR) << "GetMyDevices API failed: " << error;
228 pref_service_->SetBoolean(prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure,
229 true);
230 sync_request_->OnDidComplete(false);
231 cryptauth_client_.reset();
232 sync_request_.reset();
233 for (auto& observer : observers_)
234 observer.OnSyncFinished(SyncResult::FAILURE, DeviceChangeResult::UNCHANGED);
235 }
236
237 std::unique_ptr<SyncScheduler> CryptAuthDeviceManager::CreateSyncScheduler() {
238 return base::MakeUnique<SyncSchedulerImpl>(
239 this, base::TimeDelta::FromHours(kRefreshPeriodHours),
240 base::TimeDelta::FromMinutes(kDeviceSyncBaseRecoveryPeriodMinutes),
241 kDeviceSyncMaxJitterRatio, "CryptAuth DeviceSync");
242 }
243
244 void CryptAuthDeviceManager::OnResyncMessage() {
245 ForceSyncNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED);
246 }
247
248 void CryptAuthDeviceManager::UpdateUnlockKeysFromPrefs() {
249 const base::ListValue* unlock_key_list =
250 pref_service_->GetList(prefs::kCryptAuthDeviceSyncUnlockKeys);
251 unlock_keys_.clear();
252 for (size_t i = 0; i < unlock_key_list->GetSize(); ++i) {
253 const base::DictionaryValue* unlock_key_dictionary;
254 if (unlock_key_list->GetDictionary(i, &unlock_key_dictionary)) {
255 cryptauth::ExternalDeviceInfo unlock_key;
256 if (DictionaryToUnlockKey(*unlock_key_dictionary, &unlock_key)) {
257 unlock_keys_.push_back(unlock_key);
258 } else {
259 PA_LOG(ERROR) << "Unable to deserialize unlock key dictionary "
260 << "(index=" << i << "):\n" << *unlock_key_dictionary;
261 }
262 } else {
263 PA_LOG(ERROR) << "Can not get dictionary in list of unlock keys "
264 << "(index=" << i << "):\n" << *unlock_key_list;
265 }
266 }
267 }
268
269 void CryptAuthDeviceManager::OnSyncRequested(
270 std::unique_ptr<SyncScheduler::SyncRequest> sync_request) {
271 for (auto& observer : observers_)
272 observer.OnSyncStarted();
273
274 sync_request_ = std::move(sync_request);
275 cryptauth_client_ = client_factory_->CreateInstance();
276
277 cryptauth::InvocationReason invocation_reason =
278 cryptauth::INVOCATION_REASON_UNKNOWN;
279
280 int reason_stored_in_prefs =
281 pref_service_->GetInteger(prefs::kCryptAuthDeviceSyncReason);
282
283 // If the sync attempt is not forced, it is acceptable for CryptAuth to return
284 // a cached copy of the user's devices, rather taking a database hit for the
285 // freshest data.
286 bool is_sync_speculative =
287 reason_stored_in_prefs != cryptauth::INVOCATION_REASON_UNKNOWN;
288
289 if (cryptauth::InvocationReason_IsValid(reason_stored_in_prefs) &&
290 reason_stored_in_prefs != cryptauth::INVOCATION_REASON_UNKNOWN) {
291 invocation_reason =
292 static_cast<cryptauth::InvocationReason>(reason_stored_in_prefs);
293 } else if (GetLastSyncTime().is_null()) {
294 invocation_reason = cryptauth::INVOCATION_REASON_INITIALIZATION;
295 } else if (IsRecoveringFromFailure()) {
296 invocation_reason = cryptauth::INVOCATION_REASON_FAILURE_RECOVERY;
297 } else {
298 invocation_reason = cryptauth::INVOCATION_REASON_PERIODIC;
299 }
300
301 cryptauth::GetMyDevicesRequest request;
302 request.set_invocation_reason(invocation_reason);
303 request.set_allow_stale_read(is_sync_speculative);
304 cryptauth_client_->GetMyDevices(
305 request, base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesSuccess,
306 weak_ptr_factory_.GetWeakPtr()),
307 base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesFailure,
308 weak_ptr_factory_.GetWeakPtr()));
309 }
310
311 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698