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/cryptauth_enroller.h"
12 #include "components/proximity_auth/cryptauth/pref_names.h"
13 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
14 #include "components/proximity_auth/cryptauth/sync_scheduler_impl.h"
15 #include "components/proximity_auth/logging/logging.h"
17 namespace proximity_auth
{
21 // The number of days that an enrollment is valid. Note that we try to refresh
22 // the enrollment well before this time elapses.
23 const int kValidEnrollmentPeriodDays
= 45;
25 // The normal period between successful enrollments in days.
26 const int kEnrollmentRefreshPeriodDays
= 30;
28 // A more aggressive period between enrollments to recover when the last
29 // enrollment fails, in minutes. This is a base time that increases for each
30 // subsequent failure.
31 const int kEnrollmentBaseRecoveryPeriodMinutes
= 10;
33 // The bound on the amount to jitter the period between enrollments.
34 const double kEnrollmentMaxJitterRatio
= 0.2;
38 CryptAuthEnrollmentManager::CryptAuthEnrollmentManager(
39 scoped_ptr
<base::Clock
> clock
,
40 scoped_ptr
<CryptAuthEnrollerFactory
> enroller_factory
,
41 const std::string
& user_public_key
,
42 const std::string
& user_private_key
,
43 const cryptauth::GcmDeviceInfo
& device_info
,
44 PrefService
* pref_service
)
45 : clock_(clock
.Pass()),
46 enroller_factory_(enroller_factory
.Pass()),
47 user_public_key_(user_public_key
),
48 user_private_key_(user_private_key
),
49 device_info_(device_info
),
50 pref_service_(pref_service
),
51 weak_ptr_factory_(this) {
54 CryptAuthEnrollmentManager::~CryptAuthEnrollmentManager() {
58 void CryptAuthEnrollmentManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
59 registry
->RegisterBooleanPref(
60 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
, false);
61 registry
->RegisterDoublePref(
62 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
, 0.0);
63 registry
->RegisterIntegerPref(prefs::kCryptAuthEnrollmentReason
,
64 cryptauth::INVOCATION_REASON_UNKNOWN
);
67 void CryptAuthEnrollmentManager::Start() {
68 bool is_recovering_from_failure
=
69 pref_service_
->GetBoolean(
70 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
) ||
73 base::Time last_successful_enrollment
= GetLastEnrollmentTime();
74 base::TimeDelta elapsed_time_since_last_sync
=
75 clock_
->Now() - last_successful_enrollment
;
77 scheduler_
= CreateSyncScheduler();
78 scheduler_
->Start(elapsed_time_since_last_sync
,
79 is_recovering_from_failure
80 ? SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
81 : SyncScheduler::Strategy::PERIODIC_REFRESH
);
84 void CryptAuthEnrollmentManager::AddObserver(Observer
* observer
) {
85 observers_
.AddObserver(observer
);
88 void CryptAuthEnrollmentManager::RemoveObserver(Observer
* observer
) {
89 observers_
.RemoveObserver(observer
);
92 void CryptAuthEnrollmentManager::ForceEnrollmentNow(
93 cryptauth::InvocationReason invocation_reason
) {
94 // We store the invocation reason in a preference so that it can persist
95 // across browser restarts. If the sync fails, the next retry should still use
96 // this original reason instead of INVOCATION_REASON_FAILURE_RECOVERY.
97 pref_service_
->SetInteger(prefs::kCryptAuthEnrollmentReason
,
99 scheduler_
->ForceSync();
102 bool CryptAuthEnrollmentManager::IsEnrollmentValid() const {
103 base::Time last_enrollment_time
= GetLastEnrollmentTime();
104 return !last_enrollment_time
.is_null() &&
105 (clock_
->Now() - last_enrollment_time
) <
106 base::TimeDelta::FromDays(kValidEnrollmentPeriodDays
);
109 base::Time
CryptAuthEnrollmentManager::GetLastEnrollmentTime() const {
110 return base::Time::FromDoubleT(pref_service_
->GetDouble(
111 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
));
114 base::TimeDelta
CryptAuthEnrollmentManager::GetTimeToNextAttempt() const {
115 return scheduler_
->GetTimeToNextSync();
118 bool CryptAuthEnrollmentManager::IsEnrollmentInProgress() const {
119 return scheduler_
->GetSyncState() ==
120 SyncScheduler::SyncState::SYNC_IN_PROGRESS
;
123 bool CryptAuthEnrollmentManager::IsRecoveringFromFailure() const {
124 return scheduler_
->GetStrategy() ==
125 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
;
128 void CryptAuthEnrollmentManager::OnEnrollmentFinished(bool success
) {
130 pref_service_
->SetDouble(
131 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
,
132 clock_
->Now().ToDoubleT());
133 pref_service_
->SetInteger(prefs::kCryptAuthEnrollmentReason
,
134 cryptauth::INVOCATION_REASON_UNKNOWN
);
137 pref_service_
->SetBoolean(prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
,
140 sync_request_
->OnDidComplete(success
);
141 cryptauth_enroller_
.reset();
142 sync_request_
.reset();
143 FOR_EACH_OBSERVER(Observer
, observers_
, OnEnrollmentFinished(success
));
146 scoped_ptr
<SyncScheduler
> CryptAuthEnrollmentManager::CreateSyncScheduler() {
147 return make_scoped_ptr(new SyncSchedulerImpl(
148 this, base::TimeDelta::FromDays(kEnrollmentRefreshPeriodDays
),
149 base::TimeDelta::FromMinutes(kEnrollmentBaseRecoveryPeriodMinutes
),
150 kEnrollmentMaxJitterRatio
, "CryptAuth Enrollment"));
153 void CryptAuthEnrollmentManager::OnSyncRequested(
154 scoped_ptr
<SyncScheduler::SyncRequest
> sync_request
) {
155 FOR_EACH_OBSERVER(Observer
, observers_
, OnEnrollmentStarted());
157 sync_request_
= sync_request
.Pass();
158 cryptauth_enroller_
= enroller_factory_
->CreateInstance();
160 cryptauth::InvocationReason invocation_reason
=
161 cryptauth::INVOCATION_REASON_UNKNOWN
;
163 int reason_stored_in_prefs
=
164 pref_service_
->GetInteger(prefs::kCryptAuthEnrollmentReason
);
166 if (cryptauth::InvocationReason_IsValid(reason_stored_in_prefs
) &&
167 reason_stored_in_prefs
!= cryptauth::INVOCATION_REASON_UNKNOWN
) {
169 static_cast<cryptauth::InvocationReason
>(reason_stored_in_prefs
);
170 } else if (GetLastEnrollmentTime().is_null()) {
171 invocation_reason
= cryptauth::INVOCATION_REASON_INITIALIZATION
;
172 } else if (!IsEnrollmentValid()) {
173 invocation_reason
= cryptauth::INVOCATION_REASON_EXPIRATION
;
174 } else if (scheduler_
->GetStrategy() ==
175 SyncScheduler::Strategy::PERIODIC_REFRESH
) {
176 invocation_reason
= cryptauth::INVOCATION_REASON_PERIODIC
;
177 } else if (scheduler_
->GetStrategy() ==
178 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
) {
179 invocation_reason
= cryptauth::INVOCATION_REASON_FAILURE_RECOVERY
;
182 PA_LOG(INFO
) << "Making enrollment with reason: " << invocation_reason
;
183 cryptauth_enroller_
->Enroll(
184 user_public_key_
, user_private_key_
, device_info_
, invocation_reason
,
185 base::Bind(&CryptAuthEnrollmentManager::OnEnrollmentFinished
,
186 weak_ptr_factory_
.GetWeakPtr()));
189 } // namespace proximity_auth