blob: 48adcd93f02bc1fa744090e11d76b22f41311816 [file] [log] [blame]
// Copyright (c) 2012 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.
/**
* @fileoverview Oobe signin screen implementation.
*/
<include src="../../gaia_auth_host/gaia_auth_host.js"></include>
login.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
// Gaia loading time after which error message must be displayed and
// lazy portal check should be fired.
/** @const */ var GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC = 7;
// Maximum Gaia loading time in seconds.
/** @const */ var MAX_GAIA_LOADING_TIME_SEC = 60;
return {
EXTERNAL_API: [
'loadAuthExtension',
'updateAuthExtension',
'doReload',
'onFrameError'
],
/**
* Frame loading error code (0 - no error).
* @type {number}
* @private
*/
error_: 0,
/**
* Saved gaia auth host load params.
* @type {?string}
* @private
*/
gaiaAuthParams_: null,
/**
* Whether extension should be loaded silently.
* @type {boolean}
* @private
*/
silentLoad_: false,
/**
* Whether local version of Gaia page is used.
* @type {boolean}
* @private
*/
isLocal_: false,
/**
* Email of the user, which is logging in using offline mode.
* @type {string}
*/
email: '',
/**
* Timer id of pending load.
* @type {number}
* @private
*/
loadingTimer_: undefined,
/**
* Whether user can cancel Gaia screen.
* @type {boolean}
* @private
*/
cancelAllowed_: undefined,
/** @override */
decorate: function() {
this.gaiaAuthHost_ = new cr.login.GaiaAuthHost($('signin-frame'));
this.gaiaAuthHost_.addEventListener(
'ready', this.onAuthReady_.bind(this));
this.gaiaAuthHost_.confirmPasswordCallback =
this.onAuthConfirmPassword_.bind(this);
this.gaiaAuthHost_.noPasswordCallback =
this.onAuthNoPassword_.bind(this);
this.gaiaAuthHost_.authPageLoadedCallback =
this.onAuthPageLoaded_.bind(this);
this.updateLocalizedContent();
},
/**
* Header text of the screen.
* @type {string}
*/
get header() {
return loadTimeData.getString('signinScreenTitle');
},
/**
* Returns true if local version of Gaia is used.
* @type {boolean}
*/
get isLocal() {
return this.isLocal_;
},
/**
* Sets whether local version of Gaia is used.
* @param {boolean} value Whether local version of Gaia is used.
*/
set isLocal(value) {
this.isLocal_ = value;
chrome.send('updateOfflineLogin', [value]);
},
/**
* Shows/hides loading UI.
* @param {boolean} show True to show loading UI.
* @private
*/
showLoadingUI_: function(show) {
$('gaia-loading').hidden = !show;
this.gaiaAuthHost_.frame.hidden = show;
$('signin-right').hidden = show;
$('enterprise-info-container').hidden = show;
$('gaia-signin-divider').hidden = show;
},
/**
* Handler for Gaia loading suspiciously long timeout.
* @private
*/
onLoadingSuspiciouslyLong_: function() {
if (this != Oobe.getInstance().currentScreen)
return;
chrome.send('showLoadingTimeoutError');
this.loadingTimer_ = window.setTimeout(
this.onLoadingTimeOut_.bind(this),
(MAX_GAIA_LOADING_TIME_SEC - GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC) *
1000);
},
/**
* Handler for Gaia loading timeout.
* @private
*/
onLoadingTimeOut_: function() {
this.loadingTimer_ = undefined;
chrome.send('showLoadingTimeoutError');
},
/**
* Clears loading timer.
* @private
*/
clearLoadingTimer_: function() {
if (this.loadingTimer_) {
window.clearTimeout(this.loadingTimer_);
this.loadingTimer_ = undefined;
}
},
/**
* Sets up loading timer.
* @private
*/
startLoadingTimer_: function() {
this.clearLoadingTimer_();
this.loadingTimer_ = window.setTimeout(
this.onLoadingSuspiciouslyLong_.bind(this),
GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC * 1000);
},
/**
* Whether Gaia is loading.
* @type {boolean}
*/
get loading() {
return !$('gaia-loading').hidden;
},
set loading(loading) {
if (loading == this.loading)
return;
this.showLoadingUI_(loading);
},
/**
* Event handler that is invoked just before the frame is shown.
* @param {string} data Screen init payload. Url of auth extension start
* page.
*/
onBeforeShow: function(data) {
chrome.send('loginUIStateChanged', ['gaia-signin', true]);
$('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
// Ensure that GAIA signin (or loading UI) is actually visible.
window.webkitRequestAnimationFrame(function() {
chrome.send('loginVisible', ['gaia-loading']);
});
// Announce the name of the screen, if accessibility is on.
$('gaia-signin-aria-label').setAttribute(
'aria-label', loadTimeData.getString('signinScreenTitle'));
// Button header is always visible when sign in is presented.
// Header is hidden once GAIA reports on successful sign in.
Oobe.getInstance().headerHidden = false;
},
/**
* Event handler that is invoked just before the screen is hidden.
*/
onBeforeHide: function() {
chrome.send('loginUIStateChanged', ['gaia-signin', false]);
$('login-header-bar').signinUIState = SIGNIN_UI_STATE.HIDDEN;
},
/**
* Loads the authentication extension into the iframe.
* @param {Object} data Extension parameters bag.
* @private
*/
loadAuthExtension: function(data) {
this.silentLoad_ = data.silentLoad;
this.isLocal = data.isLocal;
this.email = '';
this.classList.toggle('saml', false);
this.updateAuthExtension(data);
var params = {};
for (var i in cr.login.GaiaAuthHost.SUPPORTED_PARAMS) {
var name = cr.login.GaiaAuthHost.SUPPORTED_PARAMS[i];
if (data[name])
params[name] = data[name];
}
if (data.localizedStrings)
params.localizedStrings = data.localizedStrings;
if (data.forceReload ||
JSON.stringify(this.gaiaAuthParams_) != JSON.stringify(params)) {
this.error_ = 0;
this.gaiaAuthHost_.load(data.useOffline,
params,
this.onAuthCompleted_.bind(this));
this.gaiaAuthParams_ = params;
this.loading = true;
this.startLoadingTimer_();
} else if (this.loading && this.error_) {
// An error has occurred, so trying to reload.
this.doReload();
}
},
/**
* Updates the authentication extension with new parameters, if needed.
* @param {Object} data New extension parameters bag.
* @private
*/
updateAuthExtension: function(data) {
var reasonLabel = $('gaia-signin-reason');
if (data.passwordChanged) {
reasonLabel.textContent =
loadTimeData.getString('signinScreenPasswordChanged');
reasonLabel.hidden = false;
} else {
reasonLabel.hidden = true;
}
$('createAccount').hidden = !data.createAccount;
$('guestSignin').hidden = !data.guestSignin;
$('createManagedUserPane').hidden = !data.managedUsersEnabled;
$('createManagedUserLinkPlaceholder').hidden =
!data.managedUsersCanCreate;
$('createManagedUserNoManagerText').hidden = data.managedUsersCanCreate;
$('createManagedUserNoManagerText').textContent =
data.managedUsersRestrictionReason;
// Allow cancellation of screen only when user pods can be displayed.
this.cancelAllowed_ = data.isShowUsers && $('pod-row').pods.length;
$('login-header-bar').allowCancel = this.cancelAllowed_;
// Sign-in right panel is hidden if all of its items are hidden.
var noRightPanel = $('gaia-signin-reason').hidden &&
$('createAccount').hidden &&
$('guestSignin').hidden &&
$('createManagedUserPane').hidden;
this.classList.toggle('no-right-panel', noRightPanel);
if (Oobe.getInstance().currentScreen === this)
Oobe.getInstance().updateScreenSize(this);
},
/**
* Invoked when the auth host notifies about an auth page is loaded.
* @param {boolean} isSAML True if the loaded auth page is SAML.
*/
onAuthPageLoaded_: function(isSAML) {
this.classList.toggle('saml', isSAML);
if (Oobe.getInstance().currentScreen === this)
Oobe.getInstance().updateScreenSize(this);
},
/**
* Invoked when the auth host emits 'ready' event.
* @private
*/
onAuthReady_: function() {
this.loading = false;
this.clearLoadingTimer_();
// Show deferred error bubble.
if (this.errorBubble_) {
this.showErrorBubble(this.errorBubble_[0], this.errorBubble_[1]);
this.errorBubble_ = undefined;
}
chrome.send('loginWebuiReady');
chrome.send('loginVisible', ['gaia-signin']);
// Warm up the user images screen.
Oobe.getInstance().preloadScreen({id: SCREEN_USER_IMAGE_PICKER});
},
/**
* Invoked when the auth host needs the user to confirm password.
* @private
*/
onAuthConfirmPassword_: function() {
this.loading = true;
Oobe.getInstance().headerHidden = false;
login.ConfirmPasswordScreen.show(
this.onConfirmPasswordCollected_.bind(this));
},
/**
* Invoked when the confirm password screen is dismissed.
* @private
*/
onConfirmPasswordCollected_: function(password) {
this.gaiaAuthHost_.verifyConfirmedPassword(password);
// Shows signin UI again without changing states.
Oobe.showScreen({id: SCREEN_GAIA_SIGNIN});
},
/**
* Inovked when the auth flow completes but no password is available.
* @param {string} email The authenticated user email.
*/
onAuthNoPassword_: function(email) {
login.MessageBoxScreen.show(
loadTimeData.getString('noPasswordWarningTitle'),
loadTimeData.getString('noPasswordWarningBody'),
loadTimeData.getString('noPasswordWarningOkButton'),
Oobe.showSigninUI);
},
/**
* Invoked when auth is completed successfully.
* @param {!Object} credentials Credentials of the completed authentication.
* @private
*/
onAuthCompleted_: function(credentials) {
if (credentials.useOffline) {
this.email = credentials.email;
chrome.send('authenticateUser',
[credentials.email, credentials.password]);
} else if (credentials.authCode) {
chrome.send('completeAuthentication',
[credentials.email,
credentials.password,
credentials.authCode]);
} else {
chrome.send('completeLogin',
[credentials.email, credentials.password]);
}
this.loading = true;
// Now that we're in logged in state header should be hidden.
Oobe.getInstance().headerHidden = true;
// Clear any error messages that were shown before login.
Oobe.clearErrors();
},
/**
* Clears input fields and switches to input mode.
* @param {boolean} takeFocus True to take focus.
* @param {boolean} forceOnline Whether online sign-in should be forced.
* If |forceOnline| is false previously used sign-in type will be used.
*/
reset: function(takeFocus, forceOnline) {
// Reload and show the sign-in UI if needed.
if (takeFocus) {
if (!forceOnline && this.isLocal) {
// Show 'Cancel' button to allow user to return to the main screen
// (e.g. this makes sense when connection is back).
Oobe.getInstance().headerHidden = false;
$('login-header-bar').signinUIState = SIGNIN_UI_STATE.GAIA_SIGNIN;
// Do nothing, since offline version is reloaded after an error comes.
} else {
Oobe.showSigninUI();
}
}
},
/**
* Reloads extension frame.
*/
doReload: function() {
this.error_ = 0;
this.gaiaAuthHost_.reload();
this.loading = true;
this.startLoadingTimer_();
},
/**
* Updates localized content of the screen that is not updated via template.
*/
updateLocalizedContent: function() {
$('createAccount').innerHTML = loadTimeData.getStringF(
'createAccount',
'<a id="createAccountLink" class="signin-link" href="#">',
'</a>');
$('guestSignin').innerHTML = loadTimeData.getStringF(
'guestSignin',
'<a id="guestSigninLink" class="signin-link" href="#">',
'</a>');
$('createManagedUserLinkPlaceholder').innerHTML = loadTimeData.getStringF(
'createLocallyManagedUser',
'<a id="createManagedUserLink" class="signin-link" href="#">',
'</a>');
$('createAccountLink').onclick = function() {
chrome.send('createAccount');
};
$('guestSigninLink').onclick = function() {
chrome.send('launchIncognito');
};
$('createManagedUserLink').onclick = function() {
chrome.send('showLocallyManagedUserCreationScreen');
};
},
/**
* Shows sign-in error bubble.
* @param {number} loginAttempts Number of login attemps tried.
* @param {HTMLElement} content Content to show in bubble.
*/
showErrorBubble: function(loginAttempts, error) {
if (this.isLocal) {
$('add-user-button').hidden = true;
$('cancel-add-user-button').hidden = false;
// Reload offline version of the sign-in extension, which will show
// error itself.
chrome.send('offlineLogin', [this.email]);
} else if (!this.loading) {
// We want to show bubble near "Email" field, but we can't calculate
// it's position because it is located inside iframe. So we only
// can hardcode some constants.
/** @const */ var ERROR_BUBBLE_OFFSET = 84;
/** @const */ var ERROR_BUBBLE_PADDING = 0;
$('bubble').showContentForElement($('login-box'),
cr.ui.Bubble.Attachment.LEFT,
error,
ERROR_BUBBLE_OFFSET,
ERROR_BUBBLE_PADDING);
} else {
// Defer the bubble until the frame has been loaded.
this.errorBubble_ = [loginAttempts, error];
}
},
/**
* Called when user canceled signin.
*/
cancel: function() {
if (!this.cancelAllowed_)
return;
$('pod-row').loadLastWallpaper();
Oobe.showScreen({id: SCREEN_ACCOUNT_PICKER});
Oobe.resetSigninUI(true);
},
/**
* Handler for iframe's error notification coming from the outside.
* For more info see C++ class 'SnifferObserver' which calls this method.
* @param {number} error Error code.
*/
onFrameError: function(error) {
this.error_ = error;
chrome.send('frameLoadingCompleted', [this.error_]);
},
};
});