1 // Copyright (c) 2012 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.
6 * @fileoverview Oobe signin screen implementation.
9 login
.createScreen('GaiaSigninScreen', 'gaia-signin', function() {
10 // Gaia loading time after which error message must be displayed and
11 // lazy portal check should be fired.
12 /** @const */ var GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC
= 7;
14 // GAIA animation guard timer. Started when GAIA page is loaded
15 // (Authenticator 'ready' event) and is intended to guard against edge cases
16 // when 'showView' message is not generated/received.
17 /** @const */ var GAIA_ANIMATION_GUARD_MILLISEC
= 300;
19 // Maximum Gaia loading time in seconds.
20 /** @const */ var MAX_GAIA_LOADING_TIME_SEC
= 60;
22 /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING
= 2535613;
24 // The help topic regarding user not being in the whitelist.
25 /** @const */ var HELP_CANT_ACCESS_ACCOUNT
= 188036;
27 // Amount of time the user has to be idle for before showing the online login
29 /** @const */ var IDLE_TIME_UNTIL_EXIT_OFFLINE_IN_MILLISECONDS
= 180 * 1000;
31 // Approximate amount of time between checks to see if we should go to the
32 // online login page when we're in the offline login page and the device is
34 /** @const */ var IDLE_TIME_CHECK_FREQUENCY
= 5 * 1000;
39 'updateAuthExtension',
44 'updateCancelButtonState',
45 'showWhitelistCheckFailedError',
49 * Frame loading error code (0 - no error).
56 * Saved gaia auth host load params.
60 gaiaAuthParams_
: null,
63 * Whether local version of Gaia page is used.
70 * Whether new Gaia flow is active.
76 * Email of the user, which is logging in using offline mode.
82 * Whether consumer management enrollment is in progress.
86 isEnrollingConsumerManagement_
: false,
89 * Timer id of pending load.
93 loadingTimer_
: undefined,
96 * Timer id of a guard timer that is fired in case 'showView' message
97 * is not received from GAIA.
101 loadAnimationGuardTimer_
: undefined,
104 * Whether we've processed 'showView' message - either from GAIA or from
109 showViewProcessed_
: undefined,
112 * Whether user can cancel Gaia screen.
116 cancelAllowed_
: undefined,
119 * Whether we should show user pods on the login screen.
123 isShowUsers_
: undefined,
126 * SAML password confirmation attempt count.
129 samlPasswordConfirmAttempt_
: 0,
132 * Do we currently have a setTimeout task running that tries to bring us
133 * back to the online login page after the user has idled for awhile? If so,
134 * then this id will be non-negative.
136 tryToGoToOnlineLoginPageCallbackId_
: -1,
139 * The most recent period of time that the user has interacted. This is
140 * only updated when the offline page is active and the device is online.
142 mostRecentUserActivity_
: Date
.now(),
145 * Whether we should show webview based signin.
149 isWebviewSignin
: false,
152 decorate: function() {
153 this.isWebviewSignin
= loadTimeData
.getValue('isWebviewSignin');
154 if (this.isWebviewSignin
) {
155 // Replace iframe with webview.
156 var webview
= this.ownerDocument
.createElement('webview');
157 webview
.id
= 'signin-frame';
158 webview
.name
= 'signin-frame';
159 webview
.hidden
= true;
160 $('signin-frame').parentNode
.replaceChild(webview
, $('signin-frame'));
161 this.gaiaAuthHost_
= new cr
.login
.GaiaAuthHost(webview
);
163 $('offline-gaia').addEventListener('authCompleted',
164 this.onAuthCompletedMessage_
.bind(this));
166 this.gaiaAuthHost_
= new cr
.login
.GaiaAuthHost($('signin-frame'));
168 this.gaiaAuthHost_
.addEventListener(
169 'ready', this.onAuthReady_
.bind(this));
170 this.gaiaAuthHost_
.addEventListener(
171 'dialogShown', this.onDialogShown_
.bind(this));
172 this.gaiaAuthHost_
.addEventListener(
173 'dialogHidden', this.onDialogHidden_
.bind(this));
174 this.gaiaAuthHost_
.addEventListener(
175 'backButton', this.onBackButton_
.bind(this));
176 this.gaiaAuthHost_
.addEventListener(
177 'showView', this.onShowView_
.bind(this));
178 this.gaiaAuthHost_
.confirmPasswordCallback
=
179 this.onAuthConfirmPassword_
.bind(this);
180 this.gaiaAuthHost_
.noPasswordCallback
=
181 this.onAuthNoPassword_
.bind(this);
182 this.gaiaAuthHost_
.insecureContentBlockedCallback
=
183 this.onInsecureContentBlocked_
.bind(this);
184 this.gaiaAuthHost_
.missingGaiaInfoCallback
=
185 this.missingGaiaInfo_
.bind(this);
186 this.gaiaAuthHost_
.samlApiUsedCallback
=
187 this.samlApiUsed_
.bind(this);
188 this.gaiaAuthHost_
.addEventListener('authDomainChange',
189 this.onAuthDomainChange_
.bind(this));
190 this.gaiaAuthHost_
.addEventListener('authFlowChange',
191 this.onAuthFlowChange_
.bind(this));
192 this.gaiaAuthHost_
.addEventListener('authCompleted',
193 this.onAuthCompletedMessage_
.bind(this));
194 this.gaiaAuthHost_
.addEventListener('loadAbort',
195 this.onLoadAbortMessage_
.bind(this));
196 this.gaiaAuthHost_
.addEventListener(
197 'identifierEntered', this.onIdentifierEnteredMessage_
.bind(this));
199 $('enterprise-info-hint-link').addEventListener('click', function(e
) {
200 chrome
.send('launchHelpApp', [HELP_TOPIC_ENTERPRISE_REPORTING
]);
204 $('back-button-item').addEventListener('click', function(e
) {
205 $('back-button-item').hidden
= true;
206 $('signin-frame').back();
210 $('close-button-item').addEventListener('click', function(e
) {
215 $('gaia-whitelist-error').addEventListener('buttonclick', function() {
216 this.showWhitelistCheckFailedError(false);
219 $('gaia-whitelist-error').addEventListener('linkclick', function() {
220 chrome
.send('launchHelpApp', [HELP_CANT_ACCESS_ACCOUNT
]);
223 this.updateLocalizedContent();
227 * Header text of the screen.
231 return loadTimeData
.getString('signinScreenTitle');
235 * Returns true if local version of Gaia is used.
239 return this.isLocal_
;
243 * Sets whether local version of Gaia is used.
244 * @param {boolean} value Whether local version of Gaia is used.
247 this.isLocal_
= value
;
248 if (this.isNewGaiaFlow
) {
249 $('signin-frame').hidden
= this.isLocal_
;
250 $('offline-gaia').hidden
= !this.isLocal_
;
252 chrome
.send('updateOfflineLogin', [value
]);
256 * This enables or disables trying to go back to the online login page
257 * after the user is idle for a few minutes, assuming that we're currently
258 * in the offline one. This is only applicable when the offline page is
259 * currently active. It is intended that when the device goes online, this
260 * gets called with true; when it goes offline, this gets called with
263 monitorOfflineIdle: function(shouldMonitor
) {
264 var ACTIVITY_EVENTS
= ['click', 'mousemove', 'keypress'];
267 // updateActivityTime_ is used as a callback for addEventListener, so we
268 // need the exact reference for removeEventListener. Because the callback
269 // needs to access the |this| as scoped inside of this function, we create
270 // a closure that uses the appropriate |this|.
272 // Unfourtantely, we cannot define this function inside of the JSON object
273 // as then we have to no way to create to capture the correct |this|
274 // reference. We define it here instead.
275 if (!self
.updateActivityTime_
) {
276 self
.updateActivityTime_ = function() {
277 self
.mostRecentUserActivity_
= Date
.now();
283 // If we're not using the offline login page or we're already
284 // monitoring, then we don't need to do anything.
285 if (self
.isLocal
=== false ||
286 self
.tryToGoToOnlineLoginPageCallbackId_
!== -1)
289 self
.mostRecentUserActivity_
= Date
.now();
290 ACTIVITY_EVENTS
.forEach(function(event
) {
291 document
.addEventListener(event
, self
.updateActivityTime_
);
294 self
.tryToGoToOnlineLoginPageCallbackId_
= setInterval(function() {
295 // If we're not in the offline page or the signin page, then we want
296 // to terminate monitoring.
297 if (self
.isLocal
=== false ||
298 Oobe
.getInstance().currentScreen
.id
!= 'gaia-signin') {
299 self
.monitorOfflineIdle(false);
303 var idleDuration
= Date
.now() - self
.mostRecentUserActivity_
;
304 if (idleDuration
> IDLE_TIME_UNTIL_EXIT_OFFLINE_IN_MILLISECONDS
) {
305 self
.isLocal
= false;
306 self
.monitorOfflineIdle(false);
308 }, IDLE_TIME_CHECK_FREQUENCY
);
313 // We're not monitoring, so we don't need to do anything.
314 if (self
.tryToGoToOnlineLoginPageCallbackId_
=== -1)
317 ACTIVITY_EVENTS
.forEach(function(event
) {
318 document
.removeEventListener(event
, self
.updateActivityTime_
);
320 clearInterval(self
.tryToGoToOnlineLoginPageCallbackId_
);
321 self
.tryToGoToOnlineLoginPageCallbackId_
= -1;
326 * Shows/hides loading UI.
327 * @param {boolean} show True to show loading UI.
330 showLoadingUI_: function(show
) {
331 $('gaia-loading').hidden
= !show
;
332 if (this.isNewGaiaFlow
&& this.isLocal
) {
333 $('offline-gaia').hidden
= show
;
335 $('signin-frame').hidden
= show
;
337 $('signin-right').hidden
= show
;
338 $('enterprise-info-container').hidden
= show
;
339 $('gaia-signin-divider').hidden
= show
;
340 this.classList
.toggle('loading', show
);
341 $('signin-frame').classList
.remove('show');
343 this.classList
.remove('auth-completed');
347 * Handler for Gaia loading suspiciously long timeout.
350 onLoadingSuspiciouslyLong_: function() {
351 if (this != Oobe
.getInstance().currentScreen
)
353 chrome
.send('showLoadingTimeoutError');
354 this.loadingTimer_
= setTimeout(
355 this.onLoadingTimeOut_
.bind(this),
356 (MAX_GAIA_LOADING_TIME_SEC
- GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC
) *
361 * Handler for Gaia loading timeout.
364 onLoadingTimeOut_: function() {
365 this.loadingTimer_
= undefined;
366 chrome
.send('showLoadingTimeoutError');
370 * Clears loading timer.
373 clearLoadingTimer_: function() {
374 if (this.loadingTimer_
) {
375 clearTimeout(this.loadingTimer_
);
376 this.loadingTimer_
= undefined;
381 * Sets up loading timer.
384 startLoadingTimer_: function() {
385 this.clearLoadingTimer_();
386 this.loadingTimer_
= setTimeout(
387 this.onLoadingSuspiciouslyLong_
.bind(this),
388 GAIA_LOADING_PORTAL_SUSSPECT_TIME_SEC
* 1000);
392 * Handler for GAIA animation guard timer.
395 onLoadAnimationGuardTimer_: function() {
396 this.loadAnimationGuardTimer_
= undefined;
401 * Clears GAIA animation guard timer.
404 clearLoadAnimationGuardTimer_: function() {
405 if (this.loadAnimationGuardTimer_
) {
406 clearTimeout(this.loadAnimationGuardTimer_
);
407 this.loadAnimationGuardTimer_
= undefined;
412 * Sets up GAIA animation guard timer.
415 startLoadAnimationGuardTimer_: function() {
416 this.clearLoadAnimationGuardTimer_();
417 this.loadAnimationGuardTimer_
= setTimeout(
418 this.onLoadAnimationGuardTimer_
.bind(this),
419 GAIA_ANIMATION_GUARD_MILLISEC
);
423 * Whether Gaia is loading.
427 return !$('gaia-loading').hidden
;
429 set loading(loading
) {
430 if (loading
== this.loading
)
433 this.showLoadingUI_(loading
);
437 * Event handler that is invoked just before the frame is shown.
438 * @param {string} data Screen init payload. Url of auth extension start
441 onBeforeShow: function(data
) {
442 chrome
.send('loginUIStateChanged', ['gaia-signin', true]);
443 $('login-header-bar').signinUIState
=
444 this.isEnrollingConsumerManagement_
?
445 SIGNIN_UI_STATE
.CONSUMER_MANAGEMENT_ENROLLMENT
:
446 SIGNIN_UI_STATE
.GAIA_SIGNIN
;
448 // Ensure that GAIA signin (or loading UI) is actually visible.
449 window
.requestAnimationFrame(function() {
450 chrome
.send('loginVisible', ['gaia-loading']);
452 $('back-button-item').disabled
= false;
453 $('back-button-item').hidden
= true;
454 $('close-button-item').disabled
= false;
455 this.classList
.toggle('loading', this.loading
);
457 // Button header is always visible when sign in is presented.
458 // Header is hidden once GAIA reports on successful sign in.
459 Oobe
.getInstance().headerHidden
= false;
462 onAfterShow: function(data
) {
463 if (!this.loading
&& this.isWebviewSignin
) {
465 $('offline-gaia').focus();
467 $('signin-frame').focus();
472 * Event handler that is invoked just before the screen is hidden.
474 onBeforeHide: function() {
475 chrome
.send('loginUIStateChanged', ['gaia-signin', false]);
476 $('login-header-bar').signinUIState
= SIGNIN_UI_STATE
.HIDDEN
;
480 * Loads the authentication extension into the iframe.
481 * @param {Object} data Extension parameters bag.
484 loadAuthExtension: function(data
) {
485 this.isNewGaiaFlow
= data
.useNewGaiaFlow
;
486 this.isLocal
= data
.isLocal
;
490 this.classList
.toggle('full-width', false);
491 this.samlPasswordConfirmAttempt_
= 0;
493 this.updateAuthExtension(data
);
496 for (var i
in cr
.login
.GaiaAuthHost
.SUPPORTED_PARAMS
) {
497 var name
= cr
.login
.GaiaAuthHost
.SUPPORTED_PARAMS
[i
];
499 params
[name
] = data
[name
];
502 if (data
.localizedStrings
)
503 params
.localizedStrings
= data
.localizedStrings
;
505 if (this.isNewGaiaFlow
) {
506 $('inner-container').classList
.add('new-gaia-flow');
507 params
.chromeType
= data
.chromeType
;
508 params
.isNewGaiaFlowChromeOS
= true;
511 if (data
.gaiaEndpoint
)
512 params
.gaiaPath
= data
.gaiaEndpoint
;
514 $('login-header-bar').newGaiaFlow
= this.isNewGaiaFlow
;
516 // Screen size could have been changed because of 'new-gaia-flow' or
517 // 'full-width' classes.
518 if (Oobe
.getInstance().currentScreen
=== this)
519 Oobe
.getInstance().updateScreenSize(this);
521 if (data
.forceReload
||
522 JSON
.stringify(this.gaiaAuthParams_
) != JSON
.stringify(params
)) {
525 var authMode
= cr
.login
.GaiaAuthHost
.AuthMode
.DEFAULT
;
527 authMode
= cr
.login
.GaiaAuthHost
.AuthMode
.OFFLINE
;
529 this.gaiaAuthParams_
= params
;
531 this.startLoadingTimer_();
533 if (this.isLocal
&& this.isNewGaiaFlow
) {
534 this.loadOffline(params
);
537 this.gaiaAuthHost_
.load(authMode
,
539 this.onAuthCompleted_
.bind(this));
541 } else if (this.loading
&& this.error_
) {
542 // An error has occurred, so trying to reload.
548 * Updates the authentication extension with new parameters, if needed.
549 * @param {Object} data New extension parameters bag.
552 updateAuthExtension: function(data
) {
553 var reasonLabel
= $('gaia-signin-reason');
554 if (data
.passwordChanged
) {
555 reasonLabel
.textContent
=
556 loadTimeData
.getString('signinScreenPasswordChanged');
557 reasonLabel
.hidden
= false;
559 reasonLabel
.hidden
= true;
562 if (this.isNewGaiaFlow
) {
563 $('login-header-bar').showCreateSupervisedButton
=
564 data
.supervisedUsersEnabled
&& data
.supervisedUsersCanCreate
;
565 $('login-header-bar').showGuestButton
= data
.guestSignin
;
567 $('createAccount').hidden
= !data
.createAccount
;
568 $('guestSignin').hidden
= !data
.guestSignin
;
569 $('createSupervisedUserPane').hidden
= !data
.supervisedUsersEnabled
;
571 $('createSupervisedUserLinkPlaceholder').hidden
=
572 !data
.supervisedUsersCanCreate
;
573 $('createSupervisedUserNoManagerText').hidden
=
574 data
.supervisedUsersCanCreate
;
575 $('createSupervisedUserNoManagerText').textContent
=
576 data
.supervisedUsersRestrictionReason
;
579 var isEnrollingConsumerManagement
= data
.isEnrollingConsumerManagement
;
580 $('consumerManagementEnrollment').hidden
= !isEnrollingConsumerManagement
;
582 this.isShowUsers_
= data
.isShowUsers
;
583 this.updateCancelButtonState();
585 this.isEnrollingConsumerManagement_
= isEnrollingConsumerManagement
;
587 // Sign-in right panel is hidden if all of its items are hidden.
588 var noRightPanel
= $('gaia-signin-reason').hidden
&&
589 $('createAccount').hidden
&&
590 $('guestSignin').hidden
&&
591 $('createSupervisedUserPane').hidden
&&
592 $('consumerManagementEnrollment').hidden
;
593 this.classList
.toggle('no-right-panel', noRightPanel
);
594 this.classList
.toggle('full-width', false);
595 if (Oobe
.getInstance().currentScreen
=== this)
596 Oobe
.getInstance().updateScreenSize(this);
600 * Updates [Cancel] button state. Allow cancellation of screen only when
601 * user pods can be displayed.
603 updateCancelButtonState: function() {
604 this.cancelAllowed_
= this.isLocal
||
605 (this.isShowUsers_
&& $('pod-row').pods
.length
);
606 $('login-header-bar').allowCancel
= this.cancelAllowed_
;
607 if (this.isNewGaiaFlow
)
608 $('close-button-item').hidden
= !this.cancelAllowed_
;
612 * Whether the current auth flow is SAML.
615 return this.gaiaAuthHost_
.authFlow
==
616 cr
.login
.GaiaAuthHost
.AuthFlow
.SAML
;
620 * Invoked when the authDomain property is changed on the GAIA host.
622 onAuthDomainChange_: function() {
623 $('saml-notice-message').textContent
= loadTimeData
.getStringF(
625 this.gaiaAuthHost_
.authDomain
);
629 * Invoked when the authFlow property is changed on the GAIA host.
630 * @param {Event} e Property change event.
632 onAuthFlowChange_: function(e
) {
633 var isSAML
= this.isSAML();
635 this.classList
.toggle('no-right-panel', isSAML
);
636 this.classList
.toggle('full-width', isSAML
);
637 $('saml-notice-container').hidden
= !isSAML
;
639 if (Oobe
.getInstance().currentScreen
=== this) {
640 Oobe
.getInstance().updateScreenSize(this);
641 $('login-header-bar').allowCancel
= isSAML
|| this.cancelAllowed_
;
642 if (this.isNewGaiaFlow
)
643 $('close-button-item').hidden
= !(isSAML
|| this.cancelAllowed_
);
648 * Invoked when the auth host emits 'ready' event.
651 onAuthReady_: function() {
652 showViewProcessed_
= false;
653 if (this.isNewGaiaFlow
)
654 this.startLoadAnimationGuardTimer_();
656 this.clearLoadingTimer_();
657 this.loading
= false;
659 if (!this.isNewGaiaFlow
)
660 this.onLoginUIVisible_();
662 // Warm up the user images screen.
663 Oobe
.getInstance().preloadScreen({id
: SCREEN_USER_IMAGE_PICKER
});
667 * Invoked when the auth host emits 'dialogShown' event.
670 onDialogShown_: function() {
671 $('back-button-item').disabled
= true;
672 $('close-button-item').disabled
= true;
676 * Invoked when the auth host emits 'dialogHidden' event.
679 onDialogHidden_: function() {
680 $('back-button-item').disabled
= false;
681 $('close-button-item').disabled
= false;
685 * Invoked when the auth host emits 'backButton' event.
688 onBackButton_: function(e
) {
689 $('back-button-item').hidden
= !e
.detail
;
690 $('login-header-bar').updateUI_();
691 $('signin-frame').focus();
695 * Invoked when the auth host emits 'showView' event or when corresponding
699 onShowView_: function(e
) {
700 if (showViewProcessed_
)
703 showViewProcessed_
= true;
704 this.clearLoadAnimationGuardTimer_();
705 $('signin-frame').classList
.add('show');
706 this.onLoginUIVisible_();
710 * Called when UI is shown.
713 onLoginUIVisible_: function() {
714 // Show deferred error bubble.
715 if (this.errorBubble_
) {
716 this.showErrorBubble(this.errorBubble_
[0], this.errorBubble_
[1]);
717 this.errorBubble_
= undefined;
720 chrome
.send('loginWebuiReady');
721 chrome
.send('loginVisible', ['gaia-signin']);
725 * Invoked when the user has successfully authenticated via SAML, the
726 * principals API was not used and the auth host needs the user to confirm
727 * the scraped password.
728 * @param {string} email The authenticated user's e-mail.
729 * @param {number} passwordCount The number of passwords that were scraped.
732 onAuthConfirmPassword_: function(email
, passwordCount
) {
734 Oobe
.getInstance().headerHidden
= false;
736 if (this.samlPasswordConfirmAttempt_
== 0)
737 chrome
.send('scrapedPasswordCount', [passwordCount
]);
739 if (this.samlPasswordConfirmAttempt_
< 2) {
740 login
.ConfirmPasswordScreen
.show(
742 this.samlPasswordConfirmAttempt_
,
743 this.onConfirmPasswordCollected_
.bind(this));
745 chrome
.send('scrapedPasswordVerificationFailed');
746 this.showFatalAuthError(
747 loadTimeData
.getString('fatalErrorMessageVerificationFailed'),
748 loadTimeData
.getString('fatalErrorTryAgainButton'));
750 if (this.isNewGaiaFlow
) {
751 this.classList
.toggle('no-right-panel', false);
752 this.classList
.toggle('full-width', false);
757 * Invoked when the confirm password screen is dismissed.
760 onConfirmPasswordCollected_: function(password
) {
761 this.samlPasswordConfirmAttempt_
++;
762 this.gaiaAuthHost_
.verifyConfirmedPassword(password
);
764 // Shows signin UI again without changing states.
765 Oobe
.showScreen({id
: SCREEN_GAIA_SIGNIN
});
769 * Inovked when the user has successfully authenticated via SAML, the
770 * principals API was not used and no passwords could be scraped.
771 * @param {string} email The authenticated user's e-mail.
773 onAuthNoPassword_: function(email
) {
774 this.showFatalAuthError(
775 loadTimeData
.getString('fatalErrorMessageNoPassword'),
776 loadTimeData
.getString('fatalErrorTryAgainButton'));
777 chrome
.send('scrapedPasswordCount', [0]);
781 * Invoked when the authentication flow had to be aborted because content
782 * served over an unencrypted connection was detected. Shows a fatal error.
783 * This method is only called on Chrome OS, where the entire authentication
784 * flow is required to be encrypted.
785 * @param {string} url The URL that was blocked.
787 onInsecureContentBlocked_: function(url
) {
788 this.showFatalAuthError(
789 loadTimeData
.getStringF('fatalErrorMessageInsecureURL', url
),
790 loadTimeData
.getString('fatalErrorDoneButton'));
794 * Shows the fatal auth error.
795 * @param {string} message The error message to show.
796 * @param {string} buttonLabel The label to display on dismiss button.
798 showFatalAuthError: function(message
, buttonLabel
) {
799 login
.FatalErrorScreen
.show(message
, buttonLabel
, Oobe
.showSigninUI
);
803 * Show fatal auth error when information is missing from GAIA.
805 missingGaiaInfo_: function() {
806 this.showFatalAuthError(
807 loadTimeData
.getString('fatalErrorMessageNoAccountDetails'),
808 loadTimeData
.getString('fatalErrorTryAgainButton'));
812 * Record that SAML API was used during sign-in.
814 samlApiUsed_: function() {
815 chrome
.send('usingSAMLAPI');
819 * Invoked when auth is completed successfully.
820 * @param {!Object} credentials Credentials of the completed authentication.
823 onAuthCompleted_: function(credentials
) {
824 if (credentials
.useOffline
) {
825 this.email
= credentials
.email
;
826 chrome
.send('authenticateUser',
828 credentials
.password
]);
829 } else if (credentials
.authCode
) {
830 if (credentials
.hasOwnProperty('authCodeOnly') &&
831 credentials
.authCodeOnly
) {
832 chrome
.send('completeAuthenticationAuthCodeOnly',
833 [credentials
.authCode
]);
835 chrome
.send('completeAuthentication', [
838 credentials
.password
,
839 credentials
.authCode
,
840 credentials
.usingSAML
,
841 credentials
.gapsCookie
845 chrome
.send('completeLogin',
848 credentials
.password
,
849 credentials
.usingSAML
]);
853 this.classList
.add('auth-completed');
854 // Now that we're in logged in state header should be hidden.
855 Oobe
.getInstance().headerHidden
= true;
856 // Clear any error messages that were shown before login.
861 * Invoked when onAuthCompleted message received.
862 * @param {!Object} e Payload of the received HTML5 message.
865 onAuthCompletedMessage_: function(e
) {
866 this.onAuthCompleted_(e
.detail
);
870 * Invoked when onLoadAbort message received.
871 * @param {!Object} e Payload of the received HTML5 message.
874 onLoadAbortMessage_: function(e
) {
875 this.onWebviewError(e
.detail
);
879 * Invoked when identifierEntered message received.
880 * @param {!Object} e Payload of the received HTML5 message.
883 onIdentifierEnteredMessage_: function(e
) {
884 this.onIdentifierEntered(e
.detail
);
888 * Clears input fields and switches to input mode.
889 * @param {boolean} takeFocus True to take focus.
890 * @param {boolean} forceOnline Whether online sign-in should be forced.
891 * If |forceOnline| is false previously used sign-in type will be used.
893 reset: function(takeFocus
, forceOnline
) {
894 // Reload and show the sign-in UI if needed.
896 if (!forceOnline
&& this.isLocal
) {
897 // Show 'Cancel' button to allow user to return to the main screen
898 // (e.g. this makes sense when connection is back).
899 Oobe
.getInstance().headerHidden
= false;
900 $('login-header-bar').signinUIState
= SIGNIN_UI_STATE
.GAIA_SIGNIN
;
901 // Do nothing, since offline version is reloaded after an error comes.
909 * Reloads extension frame.
911 doReload: function() {
915 this.gaiaAuthHost_
.reload();
917 this.startLoadingTimer_();
921 * Updates localized content of the screen that is not updated via template.
923 updateLocalizedContent: function() {
924 $('createAccount').innerHTML
= loadTimeData
.getStringF(
926 '<a id="createAccountLink" class="signin-link" href="#">',
928 $('guestSignin').innerHTML
= loadTimeData
.getStringF(
930 '<a id="guestSigninLink" class="signin-link" href="#">',
932 $('createSupervisedUserLinkPlaceholder').innerHTML
=
933 loadTimeData
.getStringF(
934 'createSupervisedUser',
935 '<a id="createSupervisedUserLink" class="signin-link" href="#">',
937 $('consumerManagementEnrollment').innerHTML
= loadTimeData
.getString(
938 'consumerManagementEnrollmentSigninMessage');
939 $('createAccountLink').addEventListener('click', function(e
) {
940 chrome
.send('createAccount');
943 $('guestSigninLink').addEventListener('click', function(e
) {
944 chrome
.send('launchIncognito');
947 $('createSupervisedUserLink').addEventListener('click', function(e
) {
948 chrome
.send('showSupervisedUserCreationScreen');
954 * Shows sign-in error bubble.
955 * @param {number} loginAttempts Number of login attemps tried.
956 * @param {HTMLElement} content Content to show in bubble.
958 showErrorBubble: function(loginAttempts
, error
) {
960 $('add-user-button').hidden
= true;
961 $('cancel-add-user-button').hidden
= false;
962 // Reload offline version of the sign-in extension, which will show
964 chrome
.send('offlineLogin', [this.email
]);
965 } else if (!this.loading
) {
966 // We want to show bubble near "Email" field, but we can't calculate
967 // it's position because it is located inside iframe. So we only
968 // can hardcode some constants.
969 /** @const */ var ERROR_BUBBLE_OFFSET
= 84;
970 /** @const */ var ERROR_BUBBLE_PADDING
= 0;
971 $('bubble').showContentForElement($('login-box'),
972 cr
.ui
.Bubble
.Attachment
.LEFT
,
975 ERROR_BUBBLE_PADDING
);
977 // Defer the bubble until the frame has been loaded.
978 this.errorBubble_
= [loginAttempts
, error
];
983 * Called when user canceled signin.
986 if (!this.cancelAllowed_
) {
987 // In OOBE signin screen, cancel is not allowed because there is
988 // no other screen to show. If user is in middle of a saml flow,
989 // reset signin screen to get out of the saml flow.
991 Oobe
.resetSigninUI(true);
996 $('offline-gaia').switchToEmailCard();
998 this.classList
.remove('whitelist-error');
1003 * Handler for iframe's error notification coming from the outside.
1004 * For more info see C++ class 'WebUILoginView' which calls this method.
1005 * @param {number} error Error code.
1006 * @param {string} url The URL that failed to load.
1008 onFrameError: function(error
, url
) {
1009 this.error_
= error
;
1010 chrome
.send('frameLoadingCompleted', [this.error_
]);
1014 * Handler for webview error handling.
1015 * @param {!Object} data Additional information about error event like:
1016 * {string} error Error code such as "ERR_INTERNET_DISCONNECTED".
1017 * {string} url The URL that failed to load.
1019 onWebviewError: function(data
) {
1020 chrome
.send('webviewLoadAborted', [data
.error
]);
1024 * Handler for identifierEntered event.
1025 * @param {!Object} data The identifier entered by user:
1026 * {string} accountIdentifier User identifier.
1028 onIdentifierEntered: function(data
) {
1029 chrome
.send('identifierEntered', [data
.accountIdentifier
]);
1033 * Sets welcome and enterpriseinfo strings for offline gaia.
1034 * Also sets callback and sends message whether we already have email and
1035 * should switch to the password screen with error.
1037 loadOffline: function(params
) {
1038 var offlineLogin
= $('offline-gaia');
1039 var strings
= params
.localizedStrings
;
1040 if ('stringEnterpriseInfo' in strings
)
1041 offlineLogin
.enterpriseInfo
= strings
['stringEnterpriseInfo'];
1042 if ('emailDomain' in params
)
1043 offlineLogin
.emailDomain
= '@' + params
['emailDomain'];
1044 offlineLogin
.setEmail(params
.email
);
1048 * Show/Hide error when user is not in whitelist. When UI is hidden
1050 * @param {boolean} show Show/hide error UI.
1051 * @param {!Object} opt_data Optional additional information.
1053 showWhitelistCheckFailedError: function(show
, opt_data
) {
1055 var isManaged
= opt_data
&& opt_data
.enterpriseManaged
;
1056 $('gaia-whitelist-error').textContent
=
1057 loadTimeData
.getValue(isManaged
? 'whitelistErrorEnterprise' :
1058 'whitelistErrorConsumer');
1061 this.classList
.toggle('whitelist-error', show
);
1062 this.loading
= !show
;
1065 Oobe
.showSigninUI();