blob: 54b787d4558e2c59a498816e2e0150f928021051 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
#include <stddef.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "ash/public/cpp/login_constants.h"
#include "ash/public/cpp/wallpaper_types.h"
#include "ash/public/interfaces/tray_action.mojom.h"
#include "base/bind.h"
#include "base/i18n/number_formatting.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part_chromeos.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/language_preferences.h"
#include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h"
#include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/hwid_checker.h"
#include "chrome/browser/chromeos/login/lock/screen_locker.h"
#include "chrome/browser/chromeos/login/lock_screen_utils.h"
#include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
#include "chrome/browser/chromeos/login/reauth_stats.h"
#include "chrome/browser/chromeos/login/screens/network_error.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/login/ui/login_display_host_webui.h"
#include "chrome/browser/chromeos/login/ui/login_display_webui.h"
#include "chrome/browser/chromeos/login/ui/login_feedback.h"
#include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h"
#include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/system/system_clock.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_metrics.h"
#include "chrome/browser/ui/ash/ime_controller_client.h"
#include "chrome/browser/ui/ash/session_controller_client_impl.h"
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
#include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
#include "chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
#include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/components/proximity_auth/screenlock_bridge.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/login/auth/key.h"
#include "chromeos/login/auth/user_context.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "components/login/localized_values_builder.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/session_manager/core/session_manager.h"
#include "components/strings/grit/components_strings.h"
#include "components/user_manager/known_user.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/ime/chromeos/ime_keyboard.h"
#include "ui/base/ime/chromeos/input_method_descriptor.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
namespace {
// Max number of users to show.
const size_t kMaxUsers = 18;
// Timeout to delay first notification about offline state for a
// current network.
constexpr base::TimeDelta kOfflineTimeout = base::TimeDelta::FromSeconds(1);
// Timeout to delay first notification about offline state when authenticating
// to a proxy.
constexpr base::TimeDelta kProxyAuthTimeout = base::TimeDelta::FromSeconds(5);
// Timeout used to prevent infinite connecting to a flaky network.
constexpr base::TimeDelta kConnectingTimeout = base::TimeDelta::FromSeconds(60);
// Max number of Gaia Reload to Show Proxy Auth Dialog.
const int kMaxGaiaReloadForProxyAuthDialog = 3;
// Type of the login screen UI that is currently presented to user.
const char kSourceGaiaSignin[] = "gaia-signin";
const char kSourceAccountPicker[] = "account-picker";
class CallOnReturn {
public:
explicit CallOnReturn(const base::Closure& callback)
: callback_(callback), call_scheduled_(false) {}
~CallOnReturn() {
if (call_scheduled_ && !callback_.is_null())
callback_.Run();
}
void CancelScheduledCall() { call_scheduled_ = false; }
void ScheduleCall() { call_scheduled_ = true; }
private:
base::Closure callback_;
bool call_scheduled_;
DISALLOW_COPY_AND_ASSIGN(CallOnReturn);
};
policy::MinimumVersionPolicyHandler* GetMinimumVersionPolicyHandler() {
return g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetMinimumVersionPolicyHandler();
}
} // namespace
namespace chromeos {
namespace {
bool IsOnline(NetworkStateInformer::State state,
NetworkError::ErrorReason reason) {
return state == NetworkStateInformer::ONLINE &&
reason != NetworkError::ERROR_REASON_PORTAL_DETECTED &&
reason != NetworkError::ERROR_REASON_LOADING_TIMEOUT;
}
bool IsBehindCaptivePortal(NetworkStateInformer::State state,
NetworkError::ErrorReason reason) {
return state == NetworkStateInformer::CAPTIVE_PORTAL ||
reason == NetworkError::ERROR_REASON_PORTAL_DETECTED;
}
bool IsProxyError(NetworkStateInformer::State state,
NetworkError::ErrorReason reason,
net::Error frame_error) {
return state == NetworkStateInformer::PROXY_AUTH_REQUIRED ||
reason == NetworkError::ERROR_REASON_PROXY_AUTH_CANCELLED ||
reason == NetworkError::ERROR_REASON_PROXY_CONNECTION_FAILED ||
(reason == NetworkError::ERROR_REASON_FRAME_ERROR &&
(frame_error == net::ERR_PROXY_CONNECTION_FAILED ||
frame_error == net::ERR_TUNNEL_CONNECTION_FAILED));
}
bool IsSigninScreen(const OobeScreenId screen) {
return screen == GaiaView::kScreenId ||
screen == OobeScreen::SCREEN_ACCOUNT_PICKER;
}
bool IsSigninScreenError(NetworkError::ErrorState error_state) {
return error_state == NetworkError::ERROR_STATE_PORTAL ||
error_state == NetworkError::ERROR_STATE_OFFLINE ||
error_state == NetworkError::ERROR_STATE_PROXY ||
error_state == NetworkError::ERROR_STATE_AUTH_EXT_TIMEOUT;
}
// Returns network name by service path.
std::string GetNetworkName(const std::string& service_path) {
const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
GetNetworkState(service_path);
if (!network)
return std::string();
return network->name();
}
} // namespace
// LoginScreenContext implementation ------------------------------------------
LoginScreenContext::LoginScreenContext() = default;
// SigninScreenHandler implementation ------------------------------------------
SigninScreenHandler::SigninScreenHandler(
JSCallsContainer* js_calls_container,
const scoped_refptr<NetworkStateInformer>& network_state_informer,
ErrorScreen* error_screen,
CoreOobeView* core_oobe_view,
GaiaScreenHandler* gaia_screen_handler)
: BaseWebUIHandler(js_calls_container),
network_state_informer_(network_state_informer),
error_screen_(error_screen),
core_oobe_view_(core_oobe_view),
caps_lock_enabled_(chromeos::input_method::InputMethodManager::Get()
->GetImeKeyboard()
->CapsLockIsEnabled()),
proxy_auth_dialog_reload_times_(kMaxGaiaReloadForProxyAuthDialog),
gaia_screen_handler_(gaia_screen_handler),
histogram_helper_(new ErrorScreensHistogramHelper("Signin")),
weak_factory_(this) {
DCHECK(network_state_informer_.get());
DCHECK(error_screen_);
DCHECK(core_oobe_view_);
DCHECK(js_calls_container);
gaia_screen_handler_->set_signin_screen_handler(this);
network_state_informer_->AddObserver(this);
registrar_.Add(this,
chrome::NOTIFICATION_AUTH_NEEDED,
content::NotificationService::AllSources());
registrar_.Add(this,
chrome::NOTIFICATION_AUTH_SUPPLIED,
content::NotificationService::AllSources());
registrar_.Add(this,
chrome::NOTIFICATION_AUTH_CANCELLED,
content::NotificationService::AllSources());
chromeos::PowerManagerClient::Get()->AddObserver(this);
chromeos::input_method::ImeKeyboard* keyboard =
chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
if (keyboard)
keyboard->AddObserver(this);
allowed_input_methods_subscription_ =
chromeos::CrosSettings::Get()->AddSettingsObserver(
chromeos::kDeviceLoginScreenInputMethods,
base::Bind(&SigninScreenHandler::OnAllowedInputMethodsChanged,
base::Unretained(this)));
TabletModeClient* tablet_mode_client = TabletModeClient::Get();
tablet_mode_client->AddObserver(this);
OnTabletModeToggled(tablet_mode_client->tablet_mode_enabled());
WallpaperControllerClient::Get()->AddObserver(this);
}
SigninScreenHandler::~SigninScreenHandler() {
if (auto* wallpaper_controller_client = WallpaperControllerClient::Get())
wallpaper_controller_client->RemoveObserver(this);
TabletModeClient::Get()->RemoveObserver(this);
OobeUI* oobe_ui = GetOobeUI();
if (oobe_ui && oobe_ui_observer_added_)
oobe_ui->RemoveObserver(this);
chromeos::PowerManagerClient::Get()->RemoveObserver(this);
chromeos::input_method::ImeKeyboard* keyboard =
chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
if (keyboard)
keyboard->RemoveObserver(this);
if (ImeControllerClient::Get()) // Can be null in tests.
ImeControllerClient::Get()->SetImesManagedByPolicy(false);
weak_factory_.InvalidateWeakPtrs();
if (delegate_)
delegate_->SetWebUIHandler(nullptr);
network_state_informer_->RemoveObserver(this);
proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr);
proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(EmptyAccountId());
}
void SigninScreenHandler::DeclareLocalizedValues(
::login::LocalizedValuesBuilder* builder) {
// Format numbers to be used on the pin keyboard.
for (int j = 0; j <= 9; j++) {
builder->Add("pinKeyboard" + base::NumberToString(j),
base::FormatNumber(int64_t{j}));
}
builder->Add("passwordHint", IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT);
builder->Add("pinKeyboardPlaceholderPin",
IDS_PIN_KEYBOARD_HINT_TEXT_PIN);
builder->Add("pinKeyboardPlaceholderPinPassword",
IDS_PIN_KEYBOARD_HINT_TEXT_PIN_PASSWORD);
builder->Add("pinKeyboardDeleteAccessibleName",
IDS_PIN_KEYBOARD_DELETE_ACCESSIBLE_NAME);
builder->Add("fingerprintHint", IDS_FINGERPRINT_HINT_TEXT);
builder->Add("fingerprintIconMessage", IDS_FINGERPRINT_ICON_MESSAGE);
builder->Add("fingerprintSigningin", IDS_FINGERPRINT_LOGIN_TEXT);
builder->Add("fingerprintSigninFailed", IDS_FINGERPRINT_LOGIN_FAILED_TEXT);
builder->Add("signingIn", IDS_LOGIN_POD_SIGNING_IN);
builder->Add("podMenuButtonAccessibleName",
IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME);
builder->Add("podMenuRemoveItemAccessibleName",
IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME);
builder->Add("passwordFieldAccessibleName",
IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME);
builder->Add("submitButtonAccessibleName",
IDS_LOGIN_POD_SUBMIT_BUTTON_ACCESSIBLE_NAME);
builder->Add("signedIn", IDS_SCREEN_LOCK_ACTIVE_USER);
builder->Add("offlineLogin", IDS_OFFLINE_LOGIN_HTML);
builder->Add("ownerUserPattern", IDS_LOGIN_POD_OWNER_USER);
builder->Add("removeUser", IDS_LOGIN_POD_REMOVE_USER);
builder->Add("errorTpmFailureTitle", IDS_LOGIN_ERROR_TPM_FAILURE_TITLE);
builder->Add("errorTpmFailureReboot", IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT);
builder->Add("errorTpmFailureRebootButton",
IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT_BUTTON);
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
builder->Add("disabledAddUserTooltip",
connector->IsEnterpriseManaged()
? IDS_DISABLED_ADD_USER_TOOLTIP_ENTERPRISE
: IDS_DISABLED_ADD_USER_TOOLTIP);
builder->Add("supervisedUserExpiredTokenWarning",
IDS_SUPERVISED_USER_EXPIRED_TOKEN_WARNING);
builder->Add("signinBannerText", IDS_LOGIN_USER_ADDING_BANNER);
// Multi-profiles related strings.
builder->Add("multiProfilesRestrictedPolicyTitle",
IDS_MULTI_PROFILES_RESTRICTED_POLICY_TITLE);
builder->Add("multiProfilesNotAllowedPolicyMsg",
IDS_MULTI_PROFILES_NOT_ALLOWED_POLICY_MSG);
builder->Add("multiProfilesPrimaryOnlyPolicyMsg",
IDS_MULTI_PROFILES_PRIMARY_ONLY_POLICY_MSG);
builder->Add("multiProfilesOwnerPrimaryOnlyMsg",
IDS_MULTI_PROFILES_OWNER_PRIMARY_ONLY_MSG);
// Strings used by password changed dialog.
builder->Add("oldPasswordHint", IDS_LOGIN_PASSWORD_CHANGED_OLD_PASSWORD_HINT);
builder->Add("oldPasswordIncorrect",
IDS_LOGIN_PASSWORD_CHANGED_INCORRECT_OLD_PASSWORD);
builder->Add("proceedAnywayButton",
IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY_BUTTON);
builder->Add("nextButtonText", IDS_OFFLINE_LOGIN_NEXT_BUTTON_TEXT);
builder->Add("forgotOldPasswordButtonText",
IDS_LOGIN_PASSWORD_CHANGED_FORGOT_PASSWORD);
builder->AddF("passwordChangedTitle", IDS_LOGIN_PASSWORD_CHANGED_TITLE,
ui::GetChromeOSDeviceName());
builder->Add("passwordChangedProceedAnywayTitle",
IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY);
builder->Add("passwordChangedTryAgain", IDS_LOGIN_PASSWORD_CHANGED_TRY_AGAIN);
builder->Add("publicAccountInfoFormat", IDS_LOGIN_PUBLIC_ACCOUNT_INFO_FORMAT);
builder->Add("publicAccountReminder",
IDS_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER);
builder->Add("publicSessionLanguageAndInput",
IDS_LOGIN_PUBLIC_SESSION_LANGUAGE_AND_INPUT);
builder->Add("publicAccountEnter", IDS_LOGIN_PUBLIC_ACCOUNT_ENTER);
builder->Add("publicAccountEnterAccessibleName",
IDS_LOGIN_PUBLIC_ACCOUNT_ENTER_ACCESSIBLE_NAME);
builder->Add("publicAccountMonitoringWarning",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_WARNING);
builder->Add("publicAccountLearnMore", IDS_LEARN_MORE);
builder->Add("publicAccountMonitoringInfo",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_INFO);
builder->Add("publicAccountMonitoringInfoItem1",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_INFO_ITEM_1);
builder->Add("publicAccountMonitoringInfoItem2",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_INFO_ITEM_2);
builder->Add("publicAccountMonitoringInfoItem3",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_INFO_ITEM_3);
builder->Add("publicAccountMonitoringInfoItem4",
IDS_LOGIN_PUBLIC_ACCOUNT_MONITORING_INFO_ITEM_4);
builder->Add("publicSessionSelectLanguage", IDS_LANGUAGE_SELECTION_SELECT);
builder->Add("publicSessionSelectKeyboard", IDS_KEYBOARD_SELECTION_SELECT);
builder->Add("removeUserWarningTextNonSyncNoStats", base::string16());
builder->Add("removeUserWarningTextNonSyncCalculating", base::string16());
builder->Add("removeUserWarningTextHistory", base::string16());
builder->Add("removeUserWarningTextPasswords", base::string16());
builder->Add("removeUserWarningTextBookmarks", base::string16());
builder->Add("removeUserWarningTextAutofill", base::string16());
builder->Add("removeUserWarningTextCalculating", base::string16());
builder->Add("removeUserWarningTextSyncNoStats", base::string16());
builder->Add("removeUserWarningTextSyncCalculating", base::string16());
builder->AddF("removeLegacySupervisedUserWarningText",
IDS_LOGIN_POD_LEGACY_SUPERVISED_USER_REMOVE_WARNING,
base::UTF8ToUTF16(
chrome::kLegacySupervisedUserManagementDisplayURL));
builder->Add("removeNonOwnerUserWarningText",
IDS_LOGIN_POD_NON_OWNER_USER_REMOVE_WARNING);
builder->Add("removeUserWarningButtonTitle",
IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON);
builder->Add("samlNotice", IDS_LOGIN_SAML_NOTICE);
builder->Add("samlNoticeWithVideo", IDS_LOGIN_SAML_NOTICE_WITH_VIDEO);
builder->AddF("confirmPasswordTitle", IDS_LOGIN_CONFIRM_PASSWORD_TITLE,
ui::GetChromeOSDeviceName());
builder->Add("manualPasswordTitle", IDS_LOGIN_MANUAL_PASSWORD_TITLE);
builder->Add("manualPasswordInputLabel",
IDS_LOGIN_MANUAL_PASSWORD_INPUT_LABEL);
builder->Add("manualPasswordMismatch",
IDS_LOGIN_MANUAL_PASSWORD_MISMATCH);
builder->Add("confirmPasswordLabel", IDS_LOGIN_CONFIRM_PASSWORD_LABEL);
builder->Add("confirmPasswordIncorrectPassword",
IDS_LOGIN_CONFIRM_PASSWORD_INCORRECT_PASSWORD);
builder->Add("accountSetupCancelDialogTitle",
IDS_LOGIN_ACCOUNT_SETUP_CANCEL_DIALOG_TITLE);
builder->Add("accountSetupCancelDialogNo",
IDS_LOGIN_ACCOUNT_SETUP_CANCEL_DIALOG_NO);
builder->Add("accountSetupCancelDialogYes",
IDS_LOGIN_ACCOUNT_SETUP_CANCEL_DIALOG_YES);
builder->Add("fatalEnrollmentError",
IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR);
builder->Add("insecureURLEnrollmentError",
IDS_ENTERPRISE_ENROLLMENT_AUTH_INSECURE_URL_ERROR);
}
void SigninScreenHandler::RegisterMessages() {
AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser);
AddCallback("completeOfflineAuthentication",
&SigninScreenHandler::HandleCompleteOfflineAuthentication);
AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito);
AddCallback("launchPublicSession",
&SigninScreenHandler::HandleLaunchPublicSession);
AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin);
AddCallback("rebootSystem", &SigninScreenHandler::HandleRebootSystem);
AddCallback("removeUser", &SigninScreenHandler::HandleRemoveUser);
AddCallback("toggleEnrollmentScreen",
&SigninScreenHandler::HandleToggleEnrollmentScreen);
AddCallback("toggleEnableDebuggingScreen",
&SigninScreenHandler::HandleToggleEnableDebuggingScreen);
AddCallback("toggleKioskEnableScreen",
&SigninScreenHandler::HandleToggleKioskEnableScreen);
AddCallback("accountPickerReady",
&SigninScreenHandler::HandleAccountPickerReady);
AddCallback("openInternetDetailDialog",
&SigninScreenHandler::HandleOpenInternetDetailDialog);
AddCallback("loginVisible", &SigninScreenHandler::HandleLoginVisible);
AddCallback("cancelPasswordChangedFlow",
&SigninScreenHandler::HandleCancelPasswordChangedFlow);
AddCallback("cancelUserAdding", &SigninScreenHandler::HandleCancelUserAdding);
AddCallback("migrateUserData", &SigninScreenHandler::HandleMigrateUserData);
AddCallback("resyncUserData", &SigninScreenHandler::HandleResyncUserData);
AddCallback("loginUIStateChanged",
&SigninScreenHandler::HandleLoginUIStateChanged);
AddCallback("showLoadingTimeoutError",
&SigninScreenHandler::HandleShowLoadingTimeoutError);
AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
AddCallback("noPodFocused", &SigninScreenHandler::HandleNoPodFocused);
AddCallback("getPublicSessionKeyboardLayouts",
&SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts);
AddCallback("getTabletModeState",
&SigninScreenHandler::HandleGetTabletModeState);
AddCallback("getDemoModeState", &SigninScreenHandler::HandleGetDemoModeState);
AddCallback("logRemoveUserWarningShown",
&SigninScreenHandler::HandleLogRemoveUserWarningShown);
AddCallback("firstIncorrectPasswordAttempt",
&SigninScreenHandler::HandleFirstIncorrectPasswordAttempt);
AddCallback("maxIncorrectPasswordAttempts",
&SigninScreenHandler::HandleMaxIncorrectPasswordAttempts);
AddCallback("sendFeedback", &SigninScreenHandler::HandleSendFeedback);
}
void SigninScreenHandler::Show(const LoginScreenContext& context,
bool oobe_ui) {
CHECK(delegate_);
// Just initialize internal fields from context and call ShowImpl().
oobe_ui_ = oobe_ui;
std::string email;
email = context.email();
gaia_screen_handler_->set_populated_email(email);
ShowImpl();
histogram_helper_->OnScreenShow();
}
void SigninScreenHandler::SetDelegate(SigninScreenHandlerDelegate* delegate) {
delegate_ = delegate;
if (delegate_)
delegate_->SetWebUIHandler(this);
}
void SigninScreenHandler::SetNativeWindowDelegate(
NativeWindowDelegate* native_window_delegate) {
native_window_delegate_ = native_window_delegate;
}
void SigninScreenHandler::OnNetworkReady() {
VLOG(1) << "OnNetworkReady() call.";
gaia_screen_handler_->MaybePreloadAuthExtension();
}
void SigninScreenHandler::UpdateState(NetworkError::ErrorReason reason) {
// ERROR_REASON_FRAME_ERROR is an explicit signal from GAIA frame so it shoud
// force network error UI update.
bool force_update = reason == NetworkError::ERROR_REASON_FRAME_ERROR;
UpdateStateInternal(reason, force_update);
}
void SigninScreenHandler::SetFocusPODCallbackForTesting(
base::Closure callback) {
test_focus_pod_callback_ = callback;
}
void SigninScreenHandler::SetOfflineTimeoutForTesting(
base::TimeDelta offline_timeout) {
is_offline_timeout_for_test_set_ = true;
offline_timeout_for_test_ = offline_timeout;
}
bool SigninScreenHandler::GetKeyboardRemappedPrefValue(
const std::string& pref_name,
int* value) {
return focused_pod_account_id_ && focused_pod_account_id_->is_valid() &&
user_manager::known_user::GetIntegerPref(*focused_pod_account_id_,
pref_name, value);
}
// SigninScreenHandler, private: -----------------------------------------------
void SigninScreenHandler::ShowImpl() {
if (!page_is_ready()) {
show_on_init_ = true;
return;
}
if (!ime_state_.get())
ime_state_ = input_method::InputMethodManager::Get()->GetActiveIMEState();
if (!oobe_ui_observer_added_) {
oobe_ui_observer_added_ = true;
GetOobeUI()->AddObserver(this);
}
if (oobe_ui_) {
// Shows new user sign-in for OOBE.
gaia_screen_handler_->OnShowAddUser();
} else {
// Populates account picker. Animation is turned off for now until we
// figure out how to make it fast enough. This will call LoadUsers.
delegate_->HandleGetUsers();
// Reset Caps Lock state when login screen is shown.
input_method::InputMethodManager::Get()
->GetImeKeyboard()
->SetCapsLockEnabled(false);
UpdateUIState(UI_STATE_ACCOUNT_PICKER);
}
}
void SigninScreenHandler::UpdateUIState(UIState ui_state) {
switch (ui_state) {
case UI_STATE_GAIA_SIGNIN:
ui_state_ = UI_STATE_GAIA_SIGNIN;
ShowScreen(GaiaView::kScreenId);
break;
case UI_STATE_ACCOUNT_PICKER:
ui_state_ = UI_STATE_ACCOUNT_PICKER;
gaia_screen_handler_->CancelShowGaiaAsync();
ShowScreen(OobeScreen::SCREEN_ACCOUNT_PICKER);
break;
default:
NOTREACHED();
break;
}
}
// TODO(antrim@): split this method into small parts.
// TODO(antrim@): move this logic to GaiaScreenHandler.
void SigninScreenHandler::UpdateStateInternal(NetworkError::ErrorReason reason,
bool force_update) {
// Do nothing once user has signed in or sign in is in progress.
// TODO(antrim): We will end up here when processing network state
// notification but no ShowSigninScreen() was called so delegate_ will be
// nullptr. Network state processing logic does not belong here.
if (delegate_ &&
(delegate_->IsUserSigninCompleted() || delegate_->IsSigninInProgress())) {
return;
}
NetworkStateInformer::State state = network_state_informer_->state();
const std::string network_path = network_state_informer_->network_path();
const std::string network_name = GetNetworkName(network_path);
// Skip "update" notification about OFFLINE state from
// NetworkStateInformer if previous notification already was
// delayed.
if ((state == NetworkStateInformer::OFFLINE ||
network_state_ignored_until_proxy_auth_) &&
!force_update && !update_state_closure_.IsCancelled()) {
return;
}
update_state_closure_.Cancel();
if ((state == NetworkStateInformer::OFFLINE && !force_update) ||
network_state_ignored_until_proxy_auth_) {
update_state_closure_.Reset(
base::Bind(&SigninScreenHandler::UpdateStateInternal,
weak_factory_.GetWeakPtr(),
reason,
true));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, update_state_closure_.callback(),
is_offline_timeout_for_test_set_ ? offline_timeout_for_test_
: kOfflineTimeout);
return;
}
// Don't show or hide error screen if we're in connecting state.
if (state == NetworkStateInformer::CONNECTING && !force_update) {
if (connecting_closure_.IsCancelled()) {
// First notification about CONNECTING state.
connecting_closure_.Reset(
base::Bind(&SigninScreenHandler::UpdateStateInternal,
weak_factory_.GetWeakPtr(),
reason,
true));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, connecting_closure_.callback(), kConnectingTimeout);
}
return;
}
connecting_closure_.Cancel();
const bool is_online = IsOnline(state, reason);
const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
const bool is_gaia_loading_timeout =
(reason == NetworkError::ERROR_REASON_LOADING_TIMEOUT);
const bool is_gaia_error =
FrameError() != net::OK && FrameError() != net::ERR_NETWORK_CHANGED;
const bool is_gaia_signin = IsGaiaVisible() || IsGaiaHiddenByError();
const bool offline_login_active =
gaia_screen_handler_->IsOfflineLoginActive();
const bool error_screen_should_overlay =
!offline_login_active && IsGaiaVisible();
const bool from_not_online_to_online_transition =
is_online && last_network_state_ != NetworkStateInformer::ONLINE;
last_network_state_ = state;
proxy_auth_dialog_need_reload_ =
(reason == NetworkError::ERROR_REASON_NETWORK_STATE_CHANGED) &&
(state == NetworkStateInformer::PROXY_AUTH_REQUIRED) &&
(proxy_auth_dialog_reload_times_ > 0);
CallOnReturn reload_gaia(base::Bind(
&SigninScreenHandler::ReloadGaia, weak_factory_.GetWeakPtr(), true));
if (is_online || !is_behind_captive_portal)
error_screen_->HideCaptivePortal();
// Hide offline message (if needed) and return if current screen is
// not a Gaia frame.
if (!is_gaia_signin) {
if (!IsSigninScreenHiddenByError())
HideOfflineMessage(state, reason);
return;
}
// Use the online login page if the user has not used the machine for awhile.
if (offline_login_active)
gaia_screen_handler_->MonitorOfflineIdle(is_online);
// Reload frame if network state is changed from {!ONLINE} -> ONLINE state.
if (reason == NetworkError::ERROR_REASON_NETWORK_STATE_CHANGED &&
from_not_online_to_online_transition) {
// Schedules a immediate retry.
LOG(WARNING) << "Retry frame load since network has been changed.";
gaia_reload_reason_ = reason;
reload_gaia.ScheduleCall();
}
if (reason == NetworkError::ERROR_REASON_PROXY_CONFIG_CHANGED &&
error_screen_should_overlay) {
// Schedules a immediate retry.
LOG(WARNING) << "Retry frameload since proxy settings has been changed.";
gaia_reload_reason_ = reason;
reload_gaia.ScheduleCall();
}
if (reason == NetworkError::ERROR_REASON_FRAME_ERROR &&
reason != gaia_reload_reason_ &&
!IsProxyError(state, reason, FrameError())) {
LOG(WARNING) << "Retry frame load due to reason: "
<< NetworkError::ErrorReasonString(reason);
gaia_reload_reason_ = reason;
reload_gaia.ScheduleCall();
}
if (is_gaia_loading_timeout) {
LOG(WARNING) << "Retry frame load due to loading timeout.";
reload_gaia.ScheduleCall();
}
if (proxy_auth_dialog_need_reload_) {
--proxy_auth_dialog_reload_times_;
LOG(WARNING) << "Retry frame load to show proxy auth dialog";
reload_gaia.ScheduleCall();
}
if ((!is_online || is_gaia_loading_timeout || is_gaia_error) &&
!offline_login_active) {
SetupAndShowOfflineMessage(state, reason);
} else {
HideOfflineMessage(state, reason);
// Cancel scheduled GAIA reload (if any) to prevent double reloads.
reload_gaia.CancelScheduledCall();
}
}
void SigninScreenHandler::SetupAndShowOfflineMessage(
NetworkStateInformer::State state,
NetworkError::ErrorReason reason) {
const std::string network_path = network_state_informer_->network_path();
const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
const bool is_proxy_error = IsProxyError(state, reason, FrameError());
const bool is_gaia_loading_timeout =
(reason == NetworkError::ERROR_REASON_LOADING_TIMEOUT);
if (is_proxy_error) {
error_screen_->SetErrorState(NetworkError::ERROR_STATE_PROXY,
std::string());
} else if (is_behind_captive_portal) {
// Do not bother a user with obsessive captive portal showing. This
// check makes captive portal being shown only once: either when error
// screen is shown for the first time or when switching from another
// error screen (offline, proxy).
if (IsGaiaVisible() ||
(error_screen_->GetErrorState() != NetworkError::ERROR_STATE_PORTAL)) {
LoginDisplayHost::default_host()->HandleDisplayCaptivePortal();
}
const std::string network_name = GetNetworkName(network_path);
error_screen_->SetErrorState(NetworkError::ERROR_STATE_PORTAL,
network_name);
} else if (is_gaia_loading_timeout) {
error_screen_->SetErrorState(NetworkError::ERROR_STATE_AUTH_EXT_TIMEOUT,
std::string());
} else {
error_screen_->SetErrorState(NetworkError::ERROR_STATE_OFFLINE,
std::string());
}
bool guest_signin_allowed = false;
bool offline_login_allowed = false;
if (IsSigninScreenError(error_screen_->GetErrorState())) {
guest_signin_allowed =
user_manager::UserManager::Get()->IsGuestSessionAllowed();
offline_login_allowed = error_screen_->GetErrorState() !=
NetworkError::ERROR_STATE_AUTH_EXT_TIMEOUT;
}
error_screen_->AllowGuestSignin(guest_signin_allowed);
error_screen_->AllowOfflineLogin(offline_login_allowed);
if (GetCurrentScreen() != ErrorScreenView::kScreenId) {
error_screen_->SetUIState(NetworkError::UI_STATE_SIGNIN);
error_screen_->SetParentScreen(GaiaView::kScreenId);
error_screen_->Show();
histogram_helper_->OnErrorShow(error_screen_->GetErrorState());
}
}
void SigninScreenHandler::HideOfflineMessage(NetworkStateInformer::State state,
NetworkError::ErrorReason reason) {
if (!IsSigninScreenHiddenByError())
return;
gaia_reload_reason_ = NetworkError::ERROR_REASON_NONE;
error_screen_->Hide();
histogram_helper_->OnErrorHide();
// Forces a reload for Gaia screen on hiding error message.
if (IsGaiaVisible() || IsGaiaHiddenByError())
ReloadGaia(reason == NetworkError::ERROR_REASON_NETWORK_STATE_CHANGED);
}
void SigninScreenHandler::ReloadGaia(bool force_reload) {
gaia_screen_handler_->ReloadGaia(force_reload);
}
void SigninScreenHandler::Initialize() {
// Preload PIN keyboard if any of the users can authenticate via PIN.
if (user_manager::UserManager::IsInitialized()) {
for (user_manager::User* user :
user_manager::UserManager::Get()->GetUnlockUsers()) {
quick_unlock::PinBackend::GetInstance()->CanAuthenticate(
user->GetAccountId(),
base::BindOnce(&SigninScreenHandler::PreloadPinKeyboard,
weak_factory_.GetWeakPtr()));
}
}
// |delegate_| is null when we are preloading the lock screen.
if (delegate_ && show_on_init_) {
show_on_init_ = false;
ShowImpl();
}
}
void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(prefs::kUsersLastInputMethod);
}
void SigninScreenHandler::OnCurrentScreenChanged(OobeScreenId current_screen,
OobeScreenId new_screen) {
if (new_screen == OobeScreen::SCREEN_ACCOUNT_PICKER) {
// Restore active IME state if returning to user pod row screen.
input_method::InputMethodManager::Get()->SetState(ime_state_);
}
}
void SigninScreenHandler::OnWallpaperColorsChanged() {
// Updates the color of the scrollable container on account picker screen,
// based on wallpaper color extraction results.
auto colors = WallpaperControllerClient::Get()->GetWallpaperColors();
SkColor dark_muted_color =
colors[static_cast<int>(ash::ColorProfileType::DARK_MUTED)];
if (dark_muted_color == ash::kInvalidWallpaperColor)
dark_muted_color = ash::login_constants::kDefaultBaseColor;
dark_muted_color = SkColorSetA(dark_muted_color, 0xFF);
SkColor base_color = color_utils::GetResultingPaintColor(
SkColorSetA(ash::login_constants::kDefaultBaseColor,
ash::login_constants::kTranslucentColorDarkenAlpha),
dark_muted_color);
SkColor scroll_color =
SkColorSetA(base_color, ash::login_constants::kScrollTranslucentAlpha);
CallJS("login.AccountPickerScreen.setOverlayColors",
color_utils::SkColorToRgbaString(dark_muted_color),
color_utils::SkColorToRgbaString(scroll_color));
}
void SigninScreenHandler::OnWallpaperBlurChanged() {
const bool show_pod_background =
!WallpaperControllerClient::Get()->IsWallpaperBlurred();
CallJS("login.AccountPickerScreen.togglePodBackground", show_pod_background);
}
void SigninScreenHandler::ClearAndEnablePassword() {
core_oobe_view_->ResetSignInUI(false);
}
void SigninScreenHandler::ClearUserPodPassword() {
core_oobe_view_->ClearUserPodPassword();
}
void SigninScreenHandler::RefocusCurrentPod() {
core_oobe_view_->RefocusCurrentPod();
}
void SigninScreenHandler::UpdatePinKeyboardState(const AccountId& account_id) {
quick_unlock::PinBackend::GetInstance()->CanAuthenticate(
account_id, base::BindOnce(&SigninScreenHandler::SetPinEnabledForUser,
weak_factory_.GetWeakPtr(), account_id));
}
void SigninScreenHandler::SetPinEnabledForUser(const AccountId& account_id,
bool is_enabled) {
CallJS("login.AccountPickerScreen.setPinEnabledForUser", account_id,
is_enabled);
}
void SigninScreenHandler::PreloadPinKeyboard(bool should_preload) {
if (should_preload)
CallJS("cr.ui.Oobe.preloadPinKeyboard");
}
void SigninScreenHandler::OnUserRemoved(const AccountId& account_id,
bool last_user_removed) {
CallJS("login.AccountPickerScreen.removeUser", account_id);
if (last_user_removed)
gaia_screen_handler_->OnShowAddUser();
}
void SigninScreenHandler::OnUserImageChanged(const user_manager::User& user) {
if (page_is_ready()) {
CallJS("login.AccountPickerScreen.updateUserImage", user.GetAccountId());
}
}
void SigninScreenHandler::OnPreferencesChanged() {
// Make sure that one of the login UI is fully functional now, otherwise
// preferences update would be picked up next time it will be shown.
if (!webui_visible_) {
LOG(WARNING) << "Login UI is not active - postponed prefs change.";
preferences_changed_delayed_ = true;
return;
}
preferences_changed_delayed_ = false;
if (!delegate_)
return;
// Send the updated user list to the UI.
delegate_->HandleGetUsers();
if (GetCurrentScreen() == OobeScreen::SCREEN_ACCOUNT_PICKER &&
delegate_->ShowUsersHasChanged() &&
!delegate_->IsShowUsers()) {
// We are at the account picker screen and the POD setting has changed
// to be disabled. We need to show the add user page.
gaia_screen_handler_->HandleShowAddUser(nullptr);
return;
}
if (delegate_->AllowNewUserChanged() || ui_state_ == UI_STATE_UNKNOWN) {
// We need to reload GAIA if UI_STATE_UNKNOWN or the allow new user setting
// has changed so that reloaded GAIA shows/hides the option to create a new
// account.
UpdateUIState(UI_STATE_ACCOUNT_PICKER);
}
}
void SigninScreenHandler::ResetSigninScreenHandlerDelegate() {
SetDelegate(nullptr);
}
void SigninScreenHandler::ShowError(int login_attempts,
const std::string& error_text,
const std::string& help_link_text,
HelpAppLauncher::HelpTopic help_topic_id) {
core_oobe_view_->ShowSignInError(login_attempts, error_text, help_link_text,
help_topic_id);
}
void SigninScreenHandler::ShowErrorScreen(LoginDisplay::SigninError error_id) {
switch (error_id) {
case LoginDisplay::TPM_ERROR:
core_oobe_view_->ShowTpmError();
break;
default:
NOTREACHED() << "Unknown sign in error";
break;
}
}
void SigninScreenHandler::ShowSigninUI(const std::string& email) {
core_oobe_view_->ShowSignInUI(email);
}
void SigninScreenHandler::ShowPasswordChangedDialog(bool show_password_error,
const std::string& email) {
core_oobe_view_->ShowPasswordChangedScreen(show_password_error, email);
}
void SigninScreenHandler::ShowWhitelistCheckFailedError() {
gaia_screen_handler_->ShowWhitelistCheckFailedError();
}
void SigninScreenHandler::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_AUTH_NEEDED: {
network_state_ignored_until_proxy_auth_ = true;
break;
}
case chrome::NOTIFICATION_AUTH_SUPPLIED: {
if (IsGaiaHiddenByError()) {
// Start listening to network state notifications immediately, hoping
// that the network will switch to ONLINE soon.
update_state_closure_.Cancel();
ReenableNetworkStateUpdatesAfterProxyAuth();
} else {
// Gaia is not hidden behind an error yet. Discard last cached network
// state notification and wait for |kProxyAuthTimeout| before
// considering network update notifications again (hoping the network
// will become ONLINE by then).
update_state_closure_.Cancel();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(
&SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth,
weak_factory_.GetWeakPtr()),
kProxyAuthTimeout);
}
break;
}
case chrome::NOTIFICATION_AUTH_CANCELLED: {
update_state_closure_.Cancel();
ReenableNetworkStateUpdatesAfterProxyAuth();
break;
}
default:
NOTREACHED() << "Unexpected notification " << type;
}
}
void SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth() {
network_state_ignored_until_proxy_auth_ = false;
}
void SigninScreenHandler::SuspendDone(const base::TimeDelta& sleep_duration) {
for (user_manager::User* user :
user_manager::UserManager::Get()->GetUnlockUsers()) {
UpdatePinKeyboardState(user->GetAccountId());
}
}
void SigninScreenHandler::OnTabletModeToggled(bool enabled) {
CallJS("login.AccountPickerScreen.setTabletModeState", enabled);
}
bool SigninScreenHandler::ShouldLoadGaia() const {
// Fetching of the extension is not started before account picker page is
// loaded because it can affect the loading speed.
// Do not load the extension for the screen locker, see crosbug.com/25018.
return !ScreenLocker::default_screen_locker() &&
is_account_picker_showing_first_time_;
}
void SigninScreenHandler::HandleAuthenticateUser(const AccountId& account_id,
const std::string& password,
bool authenticated_by_pin) {
AuthenticateExistingUser(account_id, password, authenticated_by_pin);
}
void SigninScreenHandler::AuthenticateExistingUser(const AccountId& account_id,
const std::string& password,
bool authenticated_by_pin) {
if (!delegate_)
return;
DCHECK_EQ(account_id.GetUserEmail(),
gaia::SanitizeEmail(account_id.GetUserEmail()));
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(account_id);
DCHECK(user);
UserContext user_context;
if (!user) {
LOG(ERROR) << "AuthenticateExistingUser: User not found! account type="
<< AccountId::AccountTypeToString(account_id.GetAccountType());
const user_manager::UserType user_type =
(account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
? user_manager::USER_TYPE_ACTIVE_DIRECTORY
: user_manager::UserType::USER_TYPE_REGULAR;
user_context = UserContext(user_type, account_id);
} else {
user_context = UserContext(*user);
}
user_context.SetKey(Key(password));
user_context.SetPasswordKey(Key(password));
user_context.SetIsUsingPin(authenticated_by_pin);
if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY) {
if (user_context.GetUserType() !=
user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY) {
LOG(FATAL) << "Incorrect Active Directory user type "
<< user_context.GetUserType();
}
user_context.SetIsUsingOAuth(false);
}
delegate_->Login(user_context, SigninSpecifics());
UpdatePinKeyboardState(account_id);
}
void SigninScreenHandler::HandleCompleteOfflineAuthentication(
const std::string& email,
const std::string& password) {
const std::string sanitized_email = gaia::SanitizeEmail(email);
const AccountId account_id = user_manager::known_user::GetAccountId(
sanitized_email, std::string() /* id */, AccountType::UNKNOWN);
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(account_id);
if (!user) {
LOG(ERROR)
<< "HandleCompleteOfflineAuthentication: User not found! account type="
<< AccountId::AccountTypeToString(account_id.GetAccountType());
LoginDisplayHost::default_host()->GetLoginDisplay()->ShowError(
IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, 1,
HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
return;
}
AuthenticateExistingUser(account_id, password,
false /* authenticated_by_pin */);
}
void SigninScreenHandler::HandleLaunchIncognito() {
UserContext context(user_manager::USER_TYPE_GUEST, EmptyAccountId());
if (delegate_)
delegate_->Login(context, SigninSpecifics());
}
void SigninScreenHandler::HandleLaunchPublicSession(
const AccountId& account_id,
const std::string& locale,
const std::string& input_method) {
if (!delegate_)
return;
UserContext context(user_manager::USER_TYPE_PUBLIC_ACCOUNT, account_id);
context.SetPublicSessionLocale(locale),
context.SetPublicSessionInputMethod(input_method);
delegate_->Login(context, SigninSpecifics());
}
void SigninScreenHandler::HandleOfflineLogin(const base::ListValue* args) {
if (!delegate_) {
NOTREACHED();
return;
}
std::string email;
args->GetString(0, &email);
gaia_screen_handler_->set_populated_email(email);
gaia_screen_handler_->LoadAuthExtension(true /* force */, true /* offline */);
UpdateUIState(UI_STATE_GAIA_SIGNIN);
}
void SigninScreenHandler::HandleRebootSystem() {
chromeos::PowerManagerClient::Get()->RequestRestart(
power_manager::REQUEST_RESTART_FOR_USER, "WebUI signin screen");
}
void SigninScreenHandler::HandleRemoveUser(const AccountId& account_id) {
if (delegate_ &&
(delegate_->IsUserSigninCompleted() || delegate_->IsSigninInProgress())) {
return;
}
ProfileMetrics::LogProfileDeleteUser(
ProfileMetrics::DELETE_PROFILE_USER_MANAGER);
if (!delegate_)
return;
delegate_->RemoveUser(account_id);
}
void SigninScreenHandler::HandleToggleEnrollmentScreen() {
if (delegate_)
delegate_->ShowEnterpriseEnrollmentScreen();
}
void SigninScreenHandler::HandleToggleEnableDebuggingScreen() {
if (delegate_)
delegate_->ShowEnableDebuggingScreen();
}
void SigninScreenHandler::HandleToggleKioskEnableScreen() {
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (delegate_ && !connector->IsEnterpriseManaged() &&
KioskAppManager::IsConsumerKioskEnabled() &&
LoginDisplayHost::default_host()) {
delegate_->ShowKioskEnableScreen();
}
}
void SigninScreenHandler::HandleToggleKioskAutolaunchScreen() {
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (delegate_ && !connector->IsEnterpriseManaged())
delegate_->ShowKioskAutolaunchScreen();
}
void SigninScreenHandler::LoadUsers(const user_manager::UserList& users,
const base::ListValue& users_list) {
CallJS("login.AccountPickerScreen.loadUsers", users_list);
// Enable pin for any users who can use it.
// TODO(jdufault): Cache pin state in BrowserProcess::local_state() so we
// don't need to query cryptohome every time we show login. See
// https://crbug.com/721938.
for (user_manager::User* user : users)
UpdatePinKeyboardState(user->GetAccountId());
}
void SigninScreenHandler::HandleAccountPickerReady() {
VLOG(0) << "Login WebUI >> AccountPickerReady";
if (delegate_ && !ScreenLocker::default_screen_locker() &&
!chromeos::IsMachineHWIDCorrect() &&
!oobe_ui_) {
delegate_->ShowWrongHWIDScreen();
return;
}
if (delegate_ && !oobe_ui_ && GetMinimumVersionPolicyHandler() &&
!GetMinimumVersionPolicyHandler()->RequirementsAreSatisfied()) {
delegate_->ShowUpdateRequiredScreen();
return;
}
is_account_picker_showing_first_time_ = true;
// The wallpaper may have been set before the instance is initialized, so make
// sure the colors and blur state are updated.
OnWallpaperColorsChanged();
OnWallpaperBlurChanged();
session_manager::SessionManager* session_manager =
session_manager::SessionManager::Get();
if (session_manager->session_state() == session_manager::SessionState::OOBE) {
// This updates post-OOBE shelf UI. Changes the color of shelf buttons and
// displays additional buttons that should only be shown in the login screen
session_manager->SetSessionState(
session_manager::SessionState::LOGIN_PRIMARY);
}
if (delegate_)
delegate_->OnSigninScreenReady();
}
void SigninScreenHandler::HandleOpenInternetDetailDialog() {
// Empty string opens the internet detail dialog for the default network.
InternetDetailDialog::ShowDialog("");
}
void SigninScreenHandler::HandleLoginVisible(const std::string& source) {
VLOG(1) << "Login WebUI >> loginVisible, src: " << source << ", "
<< "webui_visible_: " << webui_visible_;
if (!webui_visible_) {
// There might be multiple messages from OOBE UI so send notifications after
// the first one only.
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
TRACE_EVENT_ASYNC_END0("ui", "ShowLoginWebUI",
LoginDisplayHostWebUI::kShowLoginWebUIid);
}
webui_visible_ = true;
if (preferences_changed_delayed_)
OnPreferencesChanged();
OnAllowedInputMethodsChanged();
}
void SigninScreenHandler::HandleCancelPasswordChangedFlow(
const AccountId& account_id) {
if (account_id.is_valid()) {
RecordReauthReason(account_id, ReauthReason::PASSWORD_UPDATE_SKIPPED);
}
gaia_screen_handler_->StartClearingCookies(
base::Bind(&SigninScreenHandler::CancelPasswordChangedFlowInternal,
weak_factory_.GetWeakPtr()));
}
void SigninScreenHandler::HandleCancelUserAdding() {
if (delegate_)
delegate_->CancelUserAdding();
}
void SigninScreenHandler::HandleMigrateUserData(
const std::string& old_password) {
if (LoginDisplayHost::default_host())
LoginDisplayHost::default_host()->MigrateUserData(old_password);
}
void SigninScreenHandler::HandleResyncUserData() {
if (LoginDisplayHost::default_host())
LoginDisplayHost::default_host()->ResyncUserData();
}
void SigninScreenHandler::HandleLoginUIStateChanged(const std::string& source,
bool active) {
VLOG(0) << "Login WebUI >> active: " << active << ", "
<< "source: " << source;
if (!KioskAppManager::Get()->GetAutoLaunchApp().empty() &&
KioskAppManager::Get()->IsAutoLaunchRequested()) {
VLOG(0) << "Showing auto-launch warning";
// On slow devices, the wallpaper animation is not shown initially, so we
// must explicitly load the wallpaper. This is also the case for the
// account-picker and gaia-signin UI states.
LoginDisplayHost::default_host()->LoadSigninWallpaper();
HandleToggleKioskAutolaunchScreen();
return;
}
if (source == kSourceGaiaSignin) {
ui_state_ = UI_STATE_GAIA_SIGNIN;
} else if (source == kSourceAccountPicker) {
ui_state_ = UI_STATE_ACCOUNT_PICKER;
} else {
NOTREACHED();
return;
}
}
void SigninScreenHandler::HandleShowLoadingTimeoutError() {
UpdateState(NetworkError::ERROR_REASON_LOADING_TIMEOUT);
}
void SigninScreenHandler::HandleFocusPod(const AccountId& account_id,
bool is_large_pod) {
proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(account_id);
if (delegate_)
delegate_->CheckUserStatus(account_id);
if (!test_focus_pod_callback_.is_null())
test_focus_pod_callback_.Run();
focused_pod_account_id_ = std::make_unique<AccountId>(account_id);
const user_manager::User* user =
user_manager::UserManager::Get()->FindUser(account_id);
// |user| may be nullptr in kiosk mode or unit tests.
if (user && user->is_logged_in() && !user->is_active()) {
SessionControllerClientImpl::DoSwitchActiveUser(account_id);
} else {
lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(),
ime_state_.get());
lock_screen_utils::SetKeyboardSettings(account_id);
if (LoginDisplayHost::default_host() && is_large_pod)
LoginDisplayHost::default_host()->LoadWallpaper(account_id);
bool use_24hour_clock = false;
if (user_manager::known_user::GetBooleanPref(
account_id, prefs::kUse24HourClock, &use_24hour_clock)) {
g_browser_process->platform_part()
->GetSystemClock()
->SetLastFocusedPodHourClockType(
use_24hour_clock ? base::k24HourClock : base::k12HourClock);
}
}
}
void SigninScreenHandler::HandleNoPodFocused() {
focused_pod_account_id_.reset();
lock_screen_utils::EnforcePolicyInputMethods(std::string());
}
void SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts(
const AccountId& account_id,
const std::string& locale) {
GetKeyboardLayoutsForLocale(
base::Bind(&SigninScreenHandler::SendPublicSessionKeyboardLayouts,
weak_factory_.GetWeakPtr(), account_id, locale),
locale);
}
void SigninScreenHandler::SendPublicSessionKeyboardLayouts(
const AccountId& account_id,
const std::string& locale,
std::unique_ptr<base::ListValue> keyboard_layouts) {
CallJS("login.AccountPickerScreen.setPublicSessionKeyboardLayouts",
account_id, locale, *keyboard_layouts);
}
void SigninScreenHandler::HandleGetTabletModeState() {
CallJS("login.AccountPickerScreen.setTabletModeState",
TabletModeClient::Get()->tablet_mode_enabled());
}
void SigninScreenHandler::HandleGetDemoModeState() {
CallJS("login.AccountPickerScreen.setDemoModeState",
DemoSession::IsDeviceInDemoMode());
}
void SigninScreenHandler::HandleLogRemoveUserWarningShown() {
ProfileMetrics::LogProfileDeleteUser(
ProfileMetrics::DELETE_PROFILE_USER_MANAGER_SHOW_WARNING);
}
void SigninScreenHandler::HandleFirstIncorrectPasswordAttempt(
const AccountId& account_id) {
// TODO(ginkage): Fix this case once crbug.com/469987 is ready.
/*
if (user_manager::known_user::IsUsingSAML(email))
RecordReauthReason(email, ReauthReason::INCORRECT_SAML_PASSWORD_ENTERED);
*/
}
void SigninScreenHandler::HandleMaxIncorrectPasswordAttempts(
const AccountId& account_id) {
RecordReauthReason(account_id, ReauthReason::INCORRECT_PASSWORD_ENTERED);
}
void SigninScreenHandler::HandleSendFeedback() {
login_feedback_ =
std::make_unique<LoginFeedback>(Profile::FromWebUI(web_ui()));
login_feedback_->Request(
std::string(), base::BindOnce(&SigninScreenHandler::OnFeedbackFinished,
weak_factory_.GetWeakPtr()));
}
bool SigninScreenHandler::AllWhitelistedUsersPresent() {
CrosSettings* cros_settings = CrosSettings::Get();
bool allow_new_user = false;
cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
if (allow_new_user)
return false;
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
const user_manager::UserList& users = user_manager->GetUsers();
if (!delegate_ || users.size() > kMaxUsers) {
return false;
}
const base::ListValue* whitelist = nullptr;
if (!cros_settings->GetList(kAccountsPrefUsers, &whitelist) || !whitelist)
return false;
for (size_t i = 0; i < whitelist->GetSize(); ++i) {
std::string whitelisted_user;
// NB: Wildcards in the whitelist are also detected as not present here.
if (!whitelist->GetString(i, &whitelisted_user) ||
!user_manager->IsKnownUser(
AccountId::FromUserEmail(whitelisted_user))) {
return false;
}
}
return true;
}
void SigninScreenHandler::CancelPasswordChangedFlowInternal() {
if (delegate_)
ShowImpl();
if (LoginDisplayHost::default_host())
LoginDisplayHost::default_host()->CancelPasswordChangedFlow();
}
bool SigninScreenHandler::IsGaiaVisible() const {
return IsSigninScreen(GetCurrentScreen()) &&
ui_state_ == UI_STATE_GAIA_SIGNIN;
}
bool SigninScreenHandler::IsGaiaHiddenByError() const {
return IsSigninScreenHiddenByError() &&
ui_state_ == UI_STATE_GAIA_SIGNIN;
}
bool SigninScreenHandler::IsSigninScreenHiddenByError() const {
return (GetCurrentScreen() == ErrorScreenView::kScreenId) &&
(IsSigninScreen(error_screen_->GetParentScreen()));
}
net::Error SigninScreenHandler::FrameError() const {
return gaia_screen_handler_->frame_error();
}
void SigninScreenHandler::OnCapsLockChanged(bool enabled) {
caps_lock_enabled_ = enabled;
if (page_is_ready())
CallJS("login.AccountPickerScreen.setCapsLockState", caps_lock_enabled_);
}
void SigninScreenHandler::OnFeedbackFinished() {
login_feedback_.reset();
}
void SigninScreenHandler::OnAllowedInputMethodsChanged() {
if (!webui_visible_)
return;
if (focused_pod_account_id_) {
std::string user_input_method = lock_screen_utils::GetUserLastInputMethod(
focused_pod_account_id_->GetUserEmail());
lock_screen_utils::EnforcePolicyInputMethods(user_input_method);
} else {
lock_screen_utils::EnforcePolicyInputMethods(std::string());
}
}
} // namespace chromeos