#include "chrome/browser/signin/easy_unlock_service.h"
-#include <string>
-
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/memory/ref_counted.h"
#include "base/metrics/field_trial.h"
#include "base/prefs/pref_service.h"
-#include "base/prefs/scoped_user_pref_update.h"
#include "base/values.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
+#include "chrome/browser/signin/easy_unlock_auth_attempt.h"
#include "chrome/browser/signin/easy_unlock_service_factory.h"
#include "chrome/browser/signin/easy_unlock_service_observer.h"
-#include "chrome/browser/signin/easy_unlock_toggle_flow.h"
#include "chrome/browser/signin/screenlock_bridge.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/easy_unlock_private.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/one_shot_event.h"
#include "grit/browser_resources.h"
#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager_client.h"
-#include "components/user_manager/user_manager.h"
#endif
namespace {
-// Key name of the local device permit record dictonary in kEasyUnlockPairing.
-const char kKeyPermitAccess[] = "permitAccess";
-
-// Key name of the remote device list in kEasyUnlockPairing.
-const char kKeyDevices[] = "devices";
-
-// Key name of the phone public key in a device dictionary.
-const char kKeyPhoneId[] = "permitRecord.id";
-
extensions::ComponentLoader* GetComponentLoader(
content::BrowserContext* context) {
extensions::ExtensionSystem* extension_system =
}
virtual ~BluetoothDetector() {
- if (adapter_)
+ if (adapter_.get())
adapter_->RemoveObserver(this);
}
weak_ptr_factory_.GetWeakPtr()));
}
- bool IsPresent() const {
- return adapter_ && adapter_->IsPresent();
- }
+ bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); }
// device::BluetoothAdapter::Observer:
virtual void AdapterPresentChanged(device::BluetoothAdapter* adapter,
// chromeos::PowerManagerClient::Observer:
virtual void SuspendImminent() OVERRIDE {
service_->DisableAppIfLoaded();
- service_->screenlock_state_handler_.reset();
}
virtual void SuspendDone(const base::TimeDelta& sleep_duration) OVERRIDE {
EasyUnlockService::EasyUnlockService(Profile* profile)
: profile_(profile),
bluetooth_detector_(new BluetoothDetector(this)),
- turn_off_flow_status_(IDLE),
+ shut_down_(false),
weak_ptr_factory_(this) {
extensions::ExtensionSystem::Get(profile_)->ready().Post(
FROM_HERE,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
-void EasyUnlockService::LaunchSetup() {
- ExtensionService* service =
- extensions::ExtensionSystem::Get(profile_)->extension_service();
- const extensions::Extension* extension =
- service->GetExtensionById(extension_misc::kEasyUnlockAppId, false);
-
- OpenApplication(AppLaunchParams(
- profile_, extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW));
-}
-
bool EasyUnlockService::IsAllowed() {
-#if defined(OS_CHROMEOS)
- if (!user_manager::UserManager::Get()->IsLoggedInAsRegularUser())
+ if (shut_down_)
return false;
- if (!chromeos::ProfileHelper::IsPrimaryProfile(profile_))
+ if (!IsAllowedInternal())
return false;
+#if defined(OS_CHROMEOS)
if (!profile_->GetPrefs()->GetBoolean(prefs::kEasyUnlockAllowed))
return false;
return NULL;
if (!screenlock_state_handler_) {
screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler(
- ScreenlockBridge::GetAuthenticatedUserEmail(profile_),
- profile_->GetPrefs(),
+ GetUserEmail(),
+ GetType() == TYPE_REGULAR ? profile_->GetPrefs() : NULL,
ScreenlockBridge::Get()));
}
return screenlock_state_handler_.get();
}
-const base::DictionaryValue* EasyUnlockService::GetPermitAccess() const {
- const base::DictionaryValue* pairing_dict =
- profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
- const base::DictionaryValue* permit_dict = NULL;
- if (pairing_dict &&
- pairing_dict->GetDictionary(kKeyPermitAccess, &permit_dict)) {
- return permit_dict;
- }
-
- return NULL;
-}
+bool EasyUnlockService::UpdateScreenlockState(
+ EasyUnlockScreenlockStateHandler::State state) {
+ EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
+ if (!handler)
+ return false;
-void EasyUnlockService::SetPermitAccess(const base::DictionaryValue& permit) {
- DictionaryPrefUpdate pairing_update(profile_->GetPrefs(),
- prefs::kEasyUnlockPairing);
- pairing_update->SetWithoutPathExpansion(kKeyPermitAccess, permit.DeepCopy());
-}
+ handler->ChangeState(state);
-void EasyUnlockService::ClearPermitAccess() {
- DictionaryPrefUpdate pairing_update(profile_->GetPrefs(),
- prefs::kEasyUnlockPairing);
- pairing_update->RemoveWithoutPathExpansion(kKeyPermitAccess, NULL);
+ if (state != EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED)
+ auth_attempt_.reset();
+ return true;
}
-const base::ListValue* EasyUnlockService::GetRemoteDevices() const {
- const base::DictionaryValue* pairing_dict =
- profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
- const base::ListValue* devices = NULL;
- if (pairing_dict && pairing_dict->GetList(kKeyDevices, &devices)) {
- return devices;
- }
-
- return NULL;
+void EasyUnlockService::AttemptAuth(const std::string& user_id) {
+ auth_attempt_.reset(new EasyUnlockAuthAttempt(
+ profile_,
+ GetUserEmail(),
+ GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
+ : EasyUnlockAuthAttempt::TYPE_SIGNIN));
+ if (!auth_attempt_->Start(user_id))
+ auth_attempt_.reset();
}
-void EasyUnlockService::SetRemoteDevices(const base::ListValue& devices) {
- DictionaryPrefUpdate pairing_update(profile_->GetPrefs(),
- prefs::kEasyUnlockPairing);
- pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy());
+void EasyUnlockService::FinalizeUnlock(bool success) {
+ if (auth_attempt_)
+ auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
+ auth_attempt_.reset();
}
-void EasyUnlockService::ClearRemoteDevices() {
- DictionaryPrefUpdate pairing_update(profile_->GetPrefs(),
- prefs::kEasyUnlockPairing);
- pairing_update->RemoveWithoutPathExpansion(kKeyDevices, NULL);
+void EasyUnlockService::FinalizeSignin(const std::string& key) {
+ if (!auth_attempt_)
+ return;
+ std::string wrapped_secret = GetWrappedSecret();
+ if (!wrapped_secret.empty())
+ auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
+ auth_attempt_.reset();
}
void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) {
observers_.RemoveObserver(observer);
}
-void EasyUnlockService::RunTurnOffFlow() {
- if (turn_off_flow_status_ == PENDING)
+void EasyUnlockService::Shutdown() {
+ if (shut_down_)
return;
+ shut_down_ = true;
- SetTurnOffFlowStatus(PENDING);
-
- // Currently there should only be one registered phone.
- // TODO(xiyuan): Revisit this when server supports toggle for all or
- // there are multiple phones.
- const base::DictionaryValue* pairing_dict =
- profile_->GetPrefs()->GetDictionary(prefs::kEasyUnlockPairing);
- const base::ListValue* devices_list = NULL;
- const base::DictionaryValue* first_device = NULL;
- std::string phone_public_key;
- if (!pairing_dict || !pairing_dict->GetList(kKeyDevices, &devices_list) ||
- !devices_list || !devices_list->GetDictionary(0, &first_device) ||
- !first_device ||
- !first_device->GetString(kKeyPhoneId, &phone_public_key)) {
- LOG(WARNING) << "Bad easy unlock pairing data, wiping out local data";
- OnTurnOffFlowFinished(true);
- return;
- }
+ ShutdownInternal();
- turn_off_flow_.reset(new EasyUnlockToggleFlow(
- profile_,
- phone_public_key,
- false,
- base::Bind(&EasyUnlockService::OnTurnOffFlowFinished,
- base::Unretained(this))));
- turn_off_flow_->Start();
-}
-
-void EasyUnlockService::ResetTurnOffFlow() {
- turn_off_flow_.reset();
- SetTurnOffFlowStatus(IDLE);
-}
-
-void EasyUnlockService::Initialize() {
- registrar_.Init(profile_->GetPrefs());
- registrar_.Add(
- prefs::kEasyUnlockAllowed,
- base::Bind(&EasyUnlockService::OnPrefsChanged, base::Unretained(this)));
- OnPrefsChanged();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ ResetScreenlockState();
+ bluetooth_detector_.reset();
#if defined(OS_CHROMEOS)
- // Only start Bluetooth detection for ChromeOS since the feature is
- // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
- // previously introduced a performance regression: http://crbug.com/404482
- // Make sure not to reintroduce a performance regression if re-enabling on
- // additional platforms.
- // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
- bluetooth_detector_->Initialize();
-#endif // defined(OS_CHROMEOS)
+ power_monitor_.reset();
+#endif
}
void EasyUnlockService::LoadApp() {
if (!easy_unlock_path.empty()) {
extensions::ComponentLoader* loader = GetComponentLoader(profile_);
- if (!loader->Exists(extension_misc::kEasyUnlockAppId)) {
+ if (!loader->Exists(extension_misc::kEasyUnlockAppId))
loader->Add(IDR_EASY_UNLOCK_MANIFEST, easy_unlock_path);
- }
+
ExtensionService* extension_service =
extensions::ExtensionSystem::Get(profile_)->extension_service();
extension_service->EnableExtension(extension_misc::kEasyUnlockAppId);
+
+ NotifyUserUpdated();
}
#endif // defined(GOOGLE_CHROME_BUILD)
}
void EasyUnlockService::DisableAppIfLoaded() {
+ // Make sure lock screen state set by the extension gets reset.
+ ResetScreenlockState();
+
extensions::ComponentLoader* loader = GetComponentLoader(profile_);
if (!loader->Exists(extension_misc::kEasyUnlockAppId))
return;
extensions::Extension::DISABLE_RELOAD);
}
+void EasyUnlockService::UnloadApp() {
+ GetComponentLoader(profile_)->Remove(extension_misc::kEasyUnlockAppId);
+}
+
+void EasyUnlockService::ReloadApp() {
+ // Make sure lock screen state set by the extension gets reset.
+ ResetScreenlockState();
+
+ if (!GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId))
+ return;
+ extensions::ExtensionSystem* extension_system =
+ extensions::ExtensionSystem::Get(profile_);
+ extension_system->extension_service()->ReloadExtension(
+ extension_misc::kEasyUnlockAppId);
+ NotifyUserUpdated();
+}
+
void EasyUnlockService::UpdateAppState() {
if (IsAllowed()) {
LoadApp();
#endif
} else {
DisableAppIfLoaded();
- // Reset the screenlock state handler to make sure Screenlock state set
- // by Easy Unlock app is reset.
- screenlock_state_handler_.reset();
-
#if defined(OS_CHROMEOS)
power_monitor_.reset();
#endif
}
}
-void EasyUnlockService::OnPrefsChanged() {
- UpdateAppState();
-}
+void EasyUnlockService::NotifyUserUpdated() {
+ std::string user_id = GetUserEmail();
+ if (user_id.empty())
+ return;
-void EasyUnlockService::OnBluetoothAdapterPresentChanged() {
- UpdateAppState();
+ // Notify the easy unlock app that the user info changed.
+ extensions::api::easy_unlock_private::UserInfo info;
+ info.user_id = user_id;
+ info.logged_in = GetType() == TYPE_REGULAR;
+ info.data_ready = info.logged_in || GetRemoteDevices() != NULL;
+
+ scoped_ptr<base::ListValue> args(new base::ListValue());
+ args->Append(info.ToValue().release());
+
+ scoped_ptr<extensions::Event> event(new extensions::Event(
+ extensions::api::easy_unlock_private::OnUserInfoUpdated::kEventName,
+ args.Pass()));
+
+ extensions::EventRouter::Get(profile_)->DispatchEventToExtension(
+ extension_misc::kEasyUnlockAppId, event.Pass());
}
-void EasyUnlockService::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
- turn_off_flow_status_ = status;
+void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
FOR_EACH_OBSERVER(
EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged());
}
-void EasyUnlockService::OnTurnOffFlowFinished(bool success) {
- turn_off_flow_.reset();
-
- if (!success) {
- SetTurnOffFlowStatus(FAIL);
- return;
- }
+void EasyUnlockService::ResetScreenlockState() {
+ screenlock_state_handler_.reset();
+ auth_attempt_.reset();
+}
- ClearRemoteDevices();
- SetTurnOffFlowStatus(IDLE);
+void EasyUnlockService::Initialize() {
+ InitializeInternal();
- // Make sure lock screen state set by the extension gets reset.
- screenlock_state_handler_.reset();
+#if defined(OS_CHROMEOS)
+ // Only start Bluetooth detection for ChromeOS since the feature is
+ // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
+ // previously introduced a performance regression: http://crbug.com/404482
+ // Make sure not to reintroduce a performance regression if re-enabling on
+ // additional platforms.
+ // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
+ bluetooth_detector_->Initialize();
+#endif // defined(OS_CHROMEOS)
+}
- if (GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId)) {
- extensions::ExtensionSystem* extension_system =
- extensions::ExtensionSystem::Get(profile_);
- extension_system->extension_service()->ReloadExtension(
- extension_misc::kEasyUnlockAppId);
- }
+void EasyUnlockService::OnBluetoothAdapterPresentChanged() {
+ UpdateAppState();
}
+