1 // Copyright 2014 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 "chrome/browser/signin/easy_unlock_service_signin_chromeos.h"
7 #include "base/basictypes.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
15 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
16 #include "chromeos/login/auth/user_context.h"
20 // The maximum allowed backoff interval when waiting for cryptohome to start.
21 uint32 kMaxCryptohomeBackoffIntervalMs = 10000u;
23 // If the data load fails, the initial interval after which the load will be
24 // retried. Further intervals will exponentially increas by factor 2.
25 uint32 kInitialCryptohomeBackoffIntervalMs = 200u;
27 // Calculates the backoff interval that should be used next.
28 // |backoff| The last backoff interval used.
29 uint32 GetNextBackoffInterval(uint32 backoff) {
31 return kInitialCryptohomeBackoffIntervalMs;
36 const std::string& user_id,
38 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback);
40 // Callback passed to |LoadDataForUser()|.
41 // If |LoadDataForUser| function succeeded, it invokes |callback| with the
43 // If |LoadDataForUser| failed and further retries are allowed, schedules new
44 // |LoadDataForUser| call with some backoff. If no further retires are allowed,
45 // it invokes |callback| with the |LoadDataForUser| results.
46 void RetryDataLoadOnError(
47 const std::string& user_id,
49 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback,
51 const chromeos::EasyUnlockDeviceKeyDataList& data_list) {
53 callback.Run(success, data_list);
57 uint32 next_backoff_ms = GetNextBackoffInterval(backoff_ms);
58 if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) {
59 callback.Run(false, data_list);
63 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
65 base::Bind(&LoadDataForUser, user_id, next_backoff_ms, callback),
66 base::TimeDelta::FromMilliseconds(next_backoff_ms));
69 // Loads device data list associated with the user's Easy unlock keys.
71 const std::string& user_id,
73 const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback) {
74 chromeos::EasyUnlockKeyManager* key_manager =
75 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
78 key_manager->GetDeviceDataList(
79 chromeos::UserContext(user_id),
80 base::Bind(&RetryDataLoadOnError, user_id, backoff_ms, callback));
85 EasyUnlockServiceSignin::UserData::UserData()
86 : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) {
89 EasyUnlockServiceSignin::UserData::~UserData() {}
91 EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile)
92 : EasyUnlockService(profile),
93 allow_cryptohome_backoff_(true),
94 service_active_(false),
95 weak_ptr_factory_(this) {
98 EasyUnlockServiceSignin::~EasyUnlockServiceSignin() {
101 EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const {
102 return EasyUnlockService::TYPE_SIGNIN;
105 std::string EasyUnlockServiceSignin::GetUserEmail() const {
109 void EasyUnlockServiceSignin::LaunchSetup() {
113 const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const {
117 void EasyUnlockServiceSignin::SetPermitAccess(
118 const base::DictionaryValue& permit) {
122 void EasyUnlockServiceSignin::ClearPermitAccess() {
126 const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const {
127 const UserData* data = FindLoadedDataForCurrentUser();
130 return &data->remote_devices_value;
133 void EasyUnlockServiceSignin::SetRemoteDevices(
134 const base::ListValue& devices) {
138 void EasyUnlockServiceSignin::ClearRemoteDevices() {
142 void EasyUnlockServiceSignin::RunTurnOffFlow() {
146 void EasyUnlockServiceSignin::ResetTurnOffFlow() {
150 EasyUnlockService::TurnOffFlowStatus
151 EasyUnlockServiceSignin::GetTurnOffFlowStatus() const {
152 return EasyUnlockService::IDLE;
155 std::string EasyUnlockServiceSignin::GetChallenge() const {
156 const UserData* data = FindLoadedDataForCurrentUser();
157 // TODO(xiyuan): Use correct remote device instead of hard coded first one.
158 uint32 device_index = 0;
159 if (!data || data->devices.size() <= device_index)
160 return std::string();
161 return data->devices[device_index].challenge;
164 std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
165 const UserData* data = FindLoadedDataForCurrentUser();
166 // TODO(xiyuan): Use correct remote device instead of hard coded first one.
167 uint32 device_index = 0;
168 if (!data || data->devices.size() <= device_index)
169 return std::string();
170 return data->devices[device_index].wrapped_secret;
173 void EasyUnlockServiceSignin::InitializeInternal() {
174 if (chromeos::LoginState::Get()->IsUserLoggedIn())
177 service_active_ = true;
179 chromeos::LoginState::Get()->AddObserver(this);
180 ScreenlockBridge* screenlock_bridge = ScreenlockBridge::Get();
181 screenlock_bridge->AddObserver(this);
182 if (!screenlock_bridge->focused_user_id().empty())
183 OnFocusedUserChanged(screenlock_bridge->focused_user_id());
186 void EasyUnlockServiceSignin::ShutdownInternal() {
187 if (!service_active_)
189 service_active_ = false;
191 weak_ptr_factory_.InvalidateWeakPtrs();
192 ScreenlockBridge::Get()->RemoveObserver(this);
193 chromeos::LoginState::Get()->RemoveObserver(this);
194 STLDeleteContainerPairSecondPointers(user_data_.begin(), user_data_.end());
198 bool EasyUnlockServiceSignin::IsAllowedInternal() {
199 return service_active_ &&
201 !chromeos::LoginState::Get()->IsUserLoggedIn();
204 void EasyUnlockServiceSignin::OnScreenDidLock() {
207 void EasyUnlockServiceSignin::OnScreenDidUnlock() {
210 void EasyUnlockServiceSignin::OnFocusedUserChanged(const std::string& user_id) {
211 if (user_id_ == user_id)
214 // Setting or clearing the user_id may changed |IsAllowed| value, so in these
215 // cases update the app state. Otherwise, it's enough to notify the app the
216 // user data has been updated.
217 bool should_update_app_state = user_id_.empty() != user_id.empty();
220 ResetScreenlockState();
222 if (should_update_app_state) {
228 LoadCurrentUserDataIfNeeded();
231 void EasyUnlockServiceSignin::LoggedInStateChanged() {
232 if (!chromeos::LoginState::Get()->IsUserLoggedIn())
238 void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() {
239 if (user_id_.empty() || !service_active_)
242 std::map<std::string, UserData*>::iterator it = user_data_.find(user_id_);
243 if (it == user_data_.end())
244 user_data_.insert(std::make_pair(user_id_, new UserData()));
246 UserData* data = user_data_[user_id_];
248 if (data->state != USER_DATA_STATE_INITIAL)
250 data->state = USER_DATA_STATE_LOADING;
254 allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs,
255 base::Bind(&EasyUnlockServiceSignin::OnUserDataLoaded,
256 weak_ptr_factory_.GetWeakPtr(),
260 void EasyUnlockServiceSignin::OnUserDataLoaded(
261 const std::string& user_id,
263 const chromeos::EasyUnlockDeviceKeyDataList& devices) {
264 allow_cryptohome_backoff_ = false;
266 UserData* data = user_data_[user_id_];
267 data->state = USER_DATA_STATE_LOADED;
269 data->devices = devices;
270 chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
271 user_id, devices, &data->remote_devices_value);
274 // If the fetched data belongs to the currently focused user, notify the app
275 // that it has to refresh it's user data.
276 if (user_id == user_id_)
280 const EasyUnlockServiceSignin::UserData*
281 EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const {
282 if (user_id_.empty())
285 std::map<std::string, UserData*>::const_iterator it =
286 user_data_.find(user_id_);
287 if (it == user_data_.end())
289 if (it->second->state != USER_DATA_STATE_LOADED)