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 if (this.isNewGaiaFlow
) {
554 $('login-header-bar').showCreateSupervisedButton
=
555 data
.supervisedUsersEnabled
&& data
.supervisedUsersCanCreate
;
556 $('login-header-bar').showGuestButton
= data
.guestSignin
;
558 $('createAccount').hidden
= !data
.createAccount
;
559 $('guestSignin').hidden
= !data
.guestSignin
;
560 $('createSupervisedUserPane').hidden
= !data
.supervisedUsersEnabled
;
562 $('createSupervisedUserLinkPlaceholder').hidden
=
563 !data
.supervisedUsersCanCreate
;
564 $('createSupervisedUserNoManagerText').hidden
=
565 data
.supervisedUsersCanCreate
;
566 $('createSupervisedUserNoManagerText').textContent
=
567 data
.supervisedUsersRestrictionReason
;
570 var isEnrollingConsumerManagement
= data
.isEnrollingConsumerManagement
;
571 $('consumerManagementEnrollment').hidden
= !isEnrollingConsumerManagement
;
573 this.isShowUsers_
= data
.isShowUsers
;
574 this.updateCancelButtonState();
576 this.isEnrollingConsumerManagement_
= isEnrollingConsumerManagement
;
578 // Sign-in right panel is hidden if all of its items are hidden.
579 var noRightPanel
= $('createAccount').hidden
&&
580 $('guestSignin').hidden
&&
581 $('createSupervisedUserPane').hidden
&&
582 $('consumerManagementEnrollment').hidden
;
583 this.classList
.toggle('no-right-panel', noRightPanel
);
584 this.classList
.toggle('full-width', false);
585 if (Oobe
.getInstance().currentScreen
=== this)
586 Oobe
.getInstance().updateScreenSize(this);
590 * Updates [Cancel] button state. Allow cancellation of screen only when
591 * user pods can be displayed.
593 updateCancelButtonState: function() {
594 this.cancelAllowed_
= this.isLocal
||
595 (this.isShowUsers_
&& $('pod-row').pods
.length
);
596 $('login-header-bar').allowCancel
= this.cancelAllowed_
;
597 if (this.isNewGaiaFlow
)
598 $('close-button-item').hidden
= !this.cancelAllowed_
;
602 * Whether the current auth flow is SAML.
605 return this.gaiaAuthHost_
.authFlow
==
606 cr
.login
.GaiaAuthHost
.AuthFlow
.SAML
;
610 * Invoked when the authDomain property is changed on the GAIA host.
612 onAuthDomainChange_: function() {
613 $('saml-notice-message').textContent
= loadTimeData
.getStringF(
615 this.gaiaAuthHost_
.authDomain
);
619 * Invoked when the authFlow property is changed on the GAIA host.
620 * @param {Event} e Property change event.
622 onAuthFlowChange_: function(e
) {
623 var isSAML
= this.isSAML();
625 this.classList
.toggle('no-right-panel', isSAML
);
626 this.classList
.toggle('full-width', isSAML
);
627 $('saml-notice-container').hidden
= !isSAML
;
629 if (Oobe
.getInstance().currentScreen
=== this) {
630 Oobe
.getInstance().updateScreenSize(this);
631 $('login-header-bar').allowCancel
= isSAML
|| this.cancelAllowed_
;
632 if (this.isNewGaiaFlow
)
633 $('close-button-item').hidden
= !(isSAML
|| this.cancelAllowed_
);
638 * Invoked when the auth host emits 'ready' event.
641 onAuthReady_: function() {
642 showViewProcessed_
= false;
643 if (this.isNewGaiaFlow
)
644 this.startLoadAnimationGuardTimer_();
646 this.clearLoadingTimer_();
647 this.loading
= false;
649 if (!this.isNewGaiaFlow
)
650 this.onLoginUIVisible_();
652 // Warm up the user images screen.
653 Oobe
.getInstance().preloadScreen({id
: SCREEN_USER_IMAGE_PICKER
});
657 * Invoked when the auth host emits 'dialogShown' event.
660 onDialogShown_: function() {
661 $('back-button-item').disabled
= true;
662 $('close-button-item').disabled
= true;
666 * Invoked when the auth host emits 'dialogHidden' event.
669 onDialogHidden_: function() {
670 $('back-button-item').disabled
= false;
671 $('close-button-item').disabled
= false;
675 * Invoked when the auth host emits 'backButton' event.
678 onBackButton_: function(e
) {
679 $('back-button-item').hidden
= !e
.detail
;
680 $('login-header-bar').updateUI_();
681 $('signin-frame').focus();
685 * Invoked when the auth host emits 'showView' event or when corresponding
689 onShowView_: function(e
) {
690 if (showViewProcessed_
)
693 showViewProcessed_
= true;
694 this.clearLoadAnimationGuardTimer_();
695 $('signin-frame').classList
.add('show');
696 this.onLoginUIVisible_();
700 * Called when UI is shown.
703 onLoginUIVisible_: function() {
704 // Show deferred error bubble.
705 if (this.errorBubble_
) {
706 this.showErrorBubble(this.errorBubble_
[0], this.errorBubble_
[1]);
707 this.errorBubble_
= undefined;
710 chrome
.send('loginWebuiReady');
711 chrome
.send('loginVisible', ['gaia-signin']);
715 * Invoked when the user has successfully authenticated via SAML, the
716 * principals API was not used and the auth host needs the user to confirm
717 * the scraped password.
718 * @param {string} email The authenticated user's e-mail.
719 * @param {number} passwordCount The number of passwords that were scraped.
722 onAuthConfirmPassword_: function(email
, passwordCount
) {
724 Oobe
.getInstance().headerHidden
= false;
726 if (this.samlPasswordConfirmAttempt_
== 0)
727 chrome
.send('scrapedPasswordCount', [passwordCount
]);
729 if (this.samlPasswordConfirmAttempt_
< 2) {
730 login
.ConfirmPasswordScreen
.show(
732 this.samlPasswordConfirmAttempt_
,
733 this.onConfirmPasswordCollected_
.bind(this));
735 chrome
.send('scrapedPasswordVerificationFailed');
736 this.showFatalAuthError(
737 loadTimeData
.getString('fatalErrorMessageVerificationFailed'),
738 loadTimeData
.getString('fatalErrorTryAgainButton'));
740 if (this.isNewGaiaFlow
) {
741 this.classList
.toggle('no-right-panel', false);
742 this.classList
.toggle('full-width', false);
747 * Invoked when the confirm password screen is dismissed.
750 onConfirmPasswordCollected_: function(password
) {
751 this.samlPasswordConfirmAttempt_
++;
752 this.gaiaAuthHost_
.verifyConfirmedPassword(password
);
754 // Shows signin UI again without changing states.
755 Oobe
.showScreen({id
: SCREEN_GAIA_SIGNIN
});
759 * Inovked when the user has successfully authenticated via SAML, the
760 * principals API was not used and no passwords could be scraped.
761 * @param {string} email The authenticated user's e-mail.
763 onAuthNoPassword_: function(email
) {
764 this.showFatalAuthError(
765 loadTimeData
.getString('fatalErrorMessageNoPassword'),
766 loadTimeData
.getString('fatalErrorTryAgainButton'));
767 chrome
.send('scrapedPasswordCount', [0]);
771 * Invoked when the authentication flow had to be aborted because content
772 * served over an unencrypted connection was detected. Shows a fatal error.
773 * This method is only called on Chrome OS, where the entire authentication
774 * flow is required to be encrypted.
775 * @param {string} url The URL that was blocked.
777 onInsecureContentBlocked_: function(url
) {
778 this.showFatalAuthError(
779 loadTimeData
.getStringF('fatalErrorMessageInsecureURL', url
),
780 loadTimeData
.getString('fatalErrorDoneButton'));
784 * Shows the fatal auth error.
785 * @param {string} message The error message to show.
786 * @param {string} buttonLabel The label to display on dismiss button.
788 showFatalAuthError: function(message
, buttonLabel
) {
789 login
.FatalErrorScreen
.show(message
, buttonLabel
, Oobe
.showSigninUI
);
793 * Show fatal auth error when information is missing from GAIA.
795 missingGaiaInfo_: function() {
796 this.showFatalAuthError(
797 loadTimeData
.getString('fatalErrorMessageNoAccountDetails'),
798 loadTimeData
.getString('fatalErrorTryAgainButton'));
802 * Record that SAML API was used during sign-in.
804 samlApiUsed_: function() {
805 chrome
.send('usingSAMLAPI');
809 * Invoked when auth is completed successfully.
810 * @param {!Object} credentials Credentials of the completed authentication.
813 onAuthCompleted_: function(credentials
) {
814 if (credentials
.useOffline
) {
815 this.email
= credentials
.email
;
816 chrome
.send('authenticateUser',
818 credentials
.password
]);
819 } else if (credentials
.authCode
) {
820 if (credentials
.hasOwnProperty('authCodeOnly') &&
821 credentials
.authCodeOnly
) {
822 chrome
.send('completeAuthenticationAuthCodeOnly',
823 [credentials
.authCode
]);
825 chrome
.send('completeAuthentication', [
828 credentials
.password
,
829 credentials
.authCode
,
830 credentials
.usingSAML
,
831 credentials
.gapsCookie
835 chrome
.send('completeLogin',
838 credentials
.password
,
839 credentials
.usingSAML
]);
843 this.classList
.add('auth-completed');
844 // Now that we're in logged in state header should be hidden.
845 Oobe
.getInstance().headerHidden
= true;
846 // Clear any error messages that were shown before login.
851 * Invoked when onAuthCompleted message received.
852 * @param {!Object} e Payload of the received HTML5 message.
855 onAuthCompletedMessage_: function(e
) {
856 this.onAuthCompleted_(e
.detail
);
860 * Invoked when onLoadAbort message received.
861 * @param {!Object} e Payload of the received HTML5 message.
864 onLoadAbortMessage_: function(e
) {
865 this.onWebviewError(e
.detail
);
869 * Invoked when identifierEntered message received.
870 * @param {!Object} e Payload of the received HTML5 message.
873 onIdentifierEnteredMessage_: function(e
) {
874 this.onIdentifierEntered(e
.detail
);
878 * Clears input fields and switches to input mode.
879 * @param {boolean} takeFocus True to take focus.
880 * @param {boolean} forceOnline Whether online sign-in should be forced.
881 * If |forceOnline| is false previously used sign-in type will be used.
883 reset: function(takeFocus
, forceOnline
) {
884 // Reload and show the sign-in UI if needed.
886 if (!forceOnline
&& this.isLocal
) {
887 // Show 'Cancel' button to allow user to return to the main screen
888 // (e.g. this makes sense when connection is back).
889 Oobe
.getInstance().headerHidden
= false;
890 $('login-header-bar').signinUIState
= SIGNIN_UI_STATE
.GAIA_SIGNIN
;
891 // Do nothing, since offline version is reloaded after an error comes.
899 * Reloads extension frame.
901 doReload: function() {
905 this.gaiaAuthHost_
.reload();
907 this.startLoadingTimer_();
911 * Updates localized content of the screen that is not updated via template.
913 updateLocalizedContent: function() {
914 $('createAccount').innerHTML
= loadTimeData
.getStringF(
916 '<a id="createAccountLink" class="signin-link" href="#">',
918 $('guestSignin').innerHTML
= loadTimeData
.getStringF(
920 '<a id="guestSigninLink" class="signin-link" href="#">',
922 $('createSupervisedUserLinkPlaceholder').innerHTML
=
923 loadTimeData
.getStringF(
924 'createSupervisedUser',
925 '<a id="createSupervisedUserLink" class="signin-link" href="#">',
927 $('consumerManagementEnrollment').innerHTML
= loadTimeData
.getString(
928 'consumerManagementEnrollmentSigninMessage');
929 $('createAccountLink').addEventListener('click', function(e
) {
930 chrome
.send('createAccount');
933 $('guestSigninLink').addEventListener('click', function(e
) {
934 chrome
.send('launchIncognito');
937 $('createSupervisedUserLink').addEventListener('click', function(e
) {
938 chrome
.send('showSupervisedUserCreationScreen');
944 * Shows sign-in error bubble.
945 * @param {number} loginAttempts Number of login attemps tried.
946 * @param {HTMLElement} content Content to show in bubble.
948 showErrorBubble: function(loginAttempts
, error
) {
950 $('add-user-button').hidden
= true;
951 $('cancel-add-user-button').hidden
= false;
952 // Reload offline version of the sign-in extension, which will show
954 chrome
.send('offlineLogin', [this.email
]);
955 } else if (!this.loading
) {
956 // We want to show bubble near "Email" field, but we can't calculate
957 // it's position because it is located inside iframe. So we only
958 // can hardcode some constants.
959 /** @const */ var ERROR_BUBBLE_OFFSET
= 84;
960 /** @const */ var ERROR_BUBBLE_PADDING
= 0;
961 $('bubble').showContentForElement($('login-box'),
962 cr
.ui
.Bubble
.Attachment
.LEFT
,
965 ERROR_BUBBLE_PADDING
);
967 // Defer the bubble until the frame has been loaded.
968 this.errorBubble_
= [loginAttempts
, error
];
973 * Called when user canceled signin.
976 if (!this.cancelAllowed_
) {
977 // In OOBE signin screen, cancel is not allowed because there is
978 // no other screen to show. If user is in middle of a saml flow,
979 // reset signin screen to get out of the saml flow.
981 Oobe
.resetSigninUI(true);
986 $('offline-gaia').switchToEmailCard();
988 this.classList
.remove('whitelist-error');
993 * Handler for iframe's error notification coming from the outside.
994 * For more info see C++ class 'WebUILoginView' which calls this method.
995 * @param {number} error Error code.
996 * @param {string} url The URL that failed to load.
998 onFrameError: function(error
, url
) {
1000 chrome
.send('frameLoadingCompleted', [this.error_
]);
1004 * Handler for webview error handling.
1005 * @param {!Object} data Additional information about error event like:
1006 * {string} error Error code such as "ERR_INTERNET_DISCONNECTED".
1007 * {string} url The URL that failed to load.
1009 onWebviewError: function(data
) {
1010 chrome
.send('webviewLoadAborted', [data
.error
]);
1014 * Handler for identifierEntered event.
1015 * @param {!Object} data The identifier entered by user:
1016 * {string} accountIdentifier User identifier.
1018 onIdentifierEntered: function(data
) {
1019 chrome
.send('identifierEntered', [data
.accountIdentifier
]);
1023 * Sets welcome and enterpriseinfo strings for offline gaia.
1024 * Also sets callback and sends message whether we already have email and
1025 * should switch to the password screen with error.
1027 loadOffline: function(params
) {
1028 var offlineLogin
= $('offline-gaia');
1029 var strings
= params
.localizedStrings
;
1030 if ('stringEnterpriseInfo' in strings
)
1031 offlineLogin
.enterpriseInfo
= strings
['stringEnterpriseInfo'];
1032 if ('emailDomain' in params
)
1033 offlineLogin
.emailDomain
= '@' + params
['emailDomain'];
1034 offlineLogin
.setEmail(params
.email
);
1038 * Show/Hide error when user is not in whitelist. When UI is hidden
1040 * @param {boolean} show Show/hide error UI.
1041 * @param {!Object} opt_data Optional additional information.
1043 showWhitelistCheckFailedError: function(show
, opt_data
) {
1045 var isManaged
= opt_data
&& opt_data
.enterpriseManaged
;
1046 $('gaia-whitelist-error').textContent
=
1047 loadTimeData
.getValue(isManaged
? 'whitelistErrorEnterprise' :
1048 'whitelistErrorConsumer');
1051 this.classList
.toggle('whitelist-error', show
);
1052 this.loading
= !show
;
1055 Oobe
.showSigninUI();