Update mojo sdk to rev c02a28868825edfa57ab77947b8cb15e741c5598
[chromium-blink-merge.git] / components / proximity_auth / cryptauth / cryptauth_enrollment_manager.cc
blob888572e57cece8347cf7484be6939f5e4a8208de
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.
5 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
7 #include "base/prefs/pref_registry_simple.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/time/clock.h"
10 #include "base/time/time.h"
11 #include "components/proximity_auth/cryptauth/base64url.h"
12 #include "components/proximity_auth/cryptauth/cryptauth_enroller.h"
13 #include "components/proximity_auth/cryptauth/pref_names.h"
14 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
15 #include "components/proximity_auth/cryptauth/sync_scheduler_impl.h"
16 #include "components/proximity_auth/logging/logging.h"
18 namespace proximity_auth {
20 namespace {
22 // The number of days that an enrollment is valid. Note that we try to refresh
23 // the enrollment well before this time elapses.
24 const int kValidEnrollmentPeriodDays = 45;
26 // The normal period between successful enrollments in days.
27 const int kEnrollmentRefreshPeriodDays = 30;
29 // A more aggressive period between enrollments to recover when the last
30 // enrollment fails, in minutes. This is a base time that increases for each
31 // subsequent failure.
32 const int kEnrollmentBaseRecoveryPeriodMinutes = 10;
34 // The bound on the amount to jitter the period between enrollments.
35 const double kEnrollmentMaxJitterRatio = 0.2;
37 // The value of the device_software_package field in the device info uploaded
38 // during enrollment. This value must be the same as the app id used for GCM
39 // registration.
40 const char kDeviceSoftwarePackage[] = "com.google.chrome.cryptauth";
42 } // namespace
44 CryptAuthEnrollmentManager::CryptAuthEnrollmentManager(
45 scoped_ptr<base::Clock> clock,
46 scoped_ptr<CryptAuthEnrollerFactory> enroller_factory,
47 const std::string& user_public_key,
48 const std::string& user_private_key,
49 const cryptauth::GcmDeviceInfo& device_info,
50 CryptAuthGCMManager* gcm_manager,
51 PrefService* pref_service)
52 : clock_(clock.Pass()),
53 enroller_factory_(enroller_factory.Pass()),
54 user_public_key_(user_public_key),
55 user_private_key_(user_private_key),
56 device_info_(device_info),
57 gcm_manager_(gcm_manager),
58 pref_service_(pref_service),
59 weak_ptr_factory_(this) {}
61 CryptAuthEnrollmentManager::~CryptAuthEnrollmentManager() {
62 gcm_manager_->RemoveObserver(this);
65 // static
66 void CryptAuthEnrollmentManager::RegisterPrefs(PrefRegistrySimple* registry) {
67 registry->RegisterBooleanPref(
68 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure, false);
69 registry->RegisterDoublePref(
70 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds, 0.0);
71 registry->RegisterIntegerPref(prefs::kCryptAuthEnrollmentReason,
72 cryptauth::INVOCATION_REASON_UNKNOWN);
75 void CryptAuthEnrollmentManager::Start() {
76 gcm_manager_->AddObserver(this);
78 bool is_recovering_from_failure =
79 pref_service_->GetBoolean(
80 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure) ||
81 !IsEnrollmentValid();
83 base::Time last_successful_enrollment = GetLastEnrollmentTime();
84 base::TimeDelta elapsed_time_since_last_sync =
85 clock_->Now() - last_successful_enrollment;
87 scheduler_ = CreateSyncScheduler();
88 scheduler_->Start(elapsed_time_since_last_sync,
89 is_recovering_from_failure
90 ? SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
91 : SyncScheduler::Strategy::PERIODIC_REFRESH);
94 void CryptAuthEnrollmentManager::AddObserver(Observer* observer) {
95 observers_.AddObserver(observer);
98 void CryptAuthEnrollmentManager::RemoveObserver(Observer* observer) {
99 observers_.RemoveObserver(observer);
102 void CryptAuthEnrollmentManager::ForceEnrollmentNow(
103 cryptauth::InvocationReason invocation_reason) {
104 // We store the invocation reason in a preference so that it can persist
105 // across browser restarts. If the sync fails, the next retry should still use
106 // this original reason instead of INVOCATION_REASON_FAILURE_RECOVERY.
107 pref_service_->SetInteger(prefs::kCryptAuthEnrollmentReason,
108 invocation_reason);
109 scheduler_->ForceSync();
112 bool CryptAuthEnrollmentManager::IsEnrollmentValid() const {
113 base::Time last_enrollment_time = GetLastEnrollmentTime();
114 return !last_enrollment_time.is_null() &&
115 (clock_->Now() - last_enrollment_time) <
116 base::TimeDelta::FromDays(kValidEnrollmentPeriodDays);
119 base::Time CryptAuthEnrollmentManager::GetLastEnrollmentTime() const {
120 return base::Time::FromDoubleT(pref_service_->GetDouble(
121 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds));
124 base::TimeDelta CryptAuthEnrollmentManager::GetTimeToNextAttempt() const {
125 return scheduler_->GetTimeToNextSync();
128 bool CryptAuthEnrollmentManager::IsEnrollmentInProgress() const {
129 return scheduler_->GetSyncState() ==
130 SyncScheduler::SyncState::SYNC_IN_PROGRESS;
133 bool CryptAuthEnrollmentManager::IsRecoveringFromFailure() const {
134 return scheduler_->GetStrategy() ==
135 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY;
138 void CryptAuthEnrollmentManager::OnEnrollmentFinished(bool success) {
139 if (success) {
140 pref_service_->SetDouble(
141 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds,
142 clock_->Now().ToDoubleT());
143 pref_service_->SetInteger(prefs::kCryptAuthEnrollmentReason,
144 cryptauth::INVOCATION_REASON_UNKNOWN);
147 pref_service_->SetBoolean(prefs::kCryptAuthEnrollmentIsRecoveringFromFailure,
148 !success);
150 sync_request_->OnDidComplete(success);
151 cryptauth_enroller_.reset();
152 sync_request_.reset();
153 FOR_EACH_OBSERVER(Observer, observers_, OnEnrollmentFinished(success));
156 scoped_ptr<SyncScheduler> CryptAuthEnrollmentManager::CreateSyncScheduler() {
157 return make_scoped_ptr(new SyncSchedulerImpl(
158 this, base::TimeDelta::FromDays(kEnrollmentRefreshPeriodDays),
159 base::TimeDelta::FromMinutes(kEnrollmentBaseRecoveryPeriodMinutes),
160 kEnrollmentMaxJitterRatio, "CryptAuth Enrollment"));
163 void CryptAuthEnrollmentManager::OnGCMRegistrationResult(bool success) {
164 if (!sync_request_)
165 return;
167 PA_LOG(INFO) << "GCM registration for CryptAuth Enrollment completed: "
168 << success;
169 if (success)
170 DoCryptAuthEnrollment();
171 else
172 OnEnrollmentFinished(false);
175 void CryptAuthEnrollmentManager::OnReenrollMessage() {
176 ForceEnrollmentNow(cryptauth::INVOCATION_REASON_SERVER_INITIATED);
179 void CryptAuthEnrollmentManager::OnSyncRequested(
180 scoped_ptr<SyncScheduler::SyncRequest> sync_request) {
181 FOR_EACH_OBSERVER(Observer, observers_, OnEnrollmentStarted());
183 sync_request_ = sync_request.Pass();
185 if (gcm_manager_->GetRegistrationId().empty() ||
186 pref_service_->GetInteger(prefs::kCryptAuthEnrollmentReason) ==
187 cryptauth::INVOCATION_REASON_MANUAL) {
188 gcm_manager_->RegisterWithGCM();
189 } else {
190 DoCryptAuthEnrollment();
194 void CryptAuthEnrollmentManager::DoCryptAuthEnrollment() {
195 DCHECK(sync_request_);
196 cryptauth::InvocationReason invocation_reason =
197 cryptauth::INVOCATION_REASON_UNKNOWN;
199 int reason_stored_in_prefs =
200 pref_service_->GetInteger(prefs::kCryptAuthEnrollmentReason);
202 if (cryptauth::InvocationReason_IsValid(reason_stored_in_prefs) &&
203 reason_stored_in_prefs != cryptauth::INVOCATION_REASON_UNKNOWN) {
204 invocation_reason =
205 static_cast<cryptauth::InvocationReason>(reason_stored_in_prefs);
206 } else if (GetLastEnrollmentTime().is_null()) {
207 invocation_reason = cryptauth::INVOCATION_REASON_INITIALIZATION;
208 } else if (!IsEnrollmentValid()) {
209 invocation_reason = cryptauth::INVOCATION_REASON_EXPIRATION;
210 } else if (scheduler_->GetStrategy() ==
211 SyncScheduler::Strategy::PERIODIC_REFRESH) {
212 invocation_reason = cryptauth::INVOCATION_REASON_PERIODIC;
213 } else if (scheduler_->GetStrategy() ==
214 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY) {
215 invocation_reason = cryptauth::INVOCATION_REASON_FAILURE_RECOVERY;
218 // Fill in the current GCM registration id before enrolling, and explicitly
219 // make sure that the software package is the same as the GCM app id.
220 cryptauth::GcmDeviceInfo device_info(device_info_);
221 device_info.set_gcm_registration_id(gcm_manager_->GetRegistrationId());
222 device_info.set_device_software_package(kDeviceSoftwarePackage);
224 std::string public_key_b64;
225 Base64UrlEncode(user_public_key_, &public_key_b64);
226 PA_LOG(INFO) << "Making enrollment:\n"
227 << " public_key: " << public_key_b64 << "\n"
228 << " invocation_reason: " << invocation_reason << "\n"
229 << " gcm_registration_id: "
230 << device_info.gcm_registration_id();
232 cryptauth_enroller_ = enroller_factory_->CreateInstance();
233 cryptauth_enroller_->Enroll(
234 user_public_key_, user_private_key_, device_info, invocation_reason,
235 base::Bind(&CryptAuthEnrollmentManager::OnEnrollmentFinished,
236 weak_ptr_factory_.GetWeakPtr()));
239 } // namespace proximity_auth