diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index 12acf4439..3aa3ebfac 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -6,6 +6,9 @@ const Signals = imports.signals; const St = imports.gi.St; const Animation = imports.ui.animation; +const Batch = imports.gdm.batch; +const GdmUtil = imports.gdm.util; +const Params = imports.misc.params; const ShellEntry = imports.ui.shellEntry; const Tweener = imports.ui.tweener; const UserWidget = imports.ui.userWidget; @@ -14,16 +17,53 @@ const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; +const AuthPromptMode = { + UNLOCK_ONLY: 0, + UNLOCK_OR_LOG_IN: 1 +}; + const AuthPrompt = new Lang.Class({ Name: 'AuthPrompt', - _init: function() { + _init: function(gdmClient, mode) { + this.verifyingUser = false; + + this._gdmClient = gdmClient; + this._mode = mode; + + let reauthenticationOnly; + if (this._mode == AuthPromptMode.UNLOCK_ONLY) + reauthenticationOnly = true; + else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) + reauthenticationOnly = false; + + this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly }); + + this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); + this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage)); + this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); + this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); + this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); + this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint)); + this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint)); + + this.connect('next', Lang.bind(this, function() { + this.updateSensitivity(false); + this.startSpinning(); + if (this._queryingService) { + this._userVerifier.answerQuery(this._queryingService, this._entry.text); + } else { + this._preemptiveAnswer = this._entry.text; + } + })); + this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', vertical: true }); + this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this.actor.connect('key-press-event', Lang.bind(this, function(actor, event) { if (event.get_key_symbol() == Clutter.KEY_Escape) { - this.emit('cancel'); + this.cancel(); } })); @@ -78,6 +118,10 @@ const AuthPrompt = new Lang.Class({ this._defaultButtonWell.add_child(this._spinner.actor); }, + _onDestroy: function() { + this._userVerifier.clear(); + }, + _initButtons: function() { this.cancelButton = new St.Button({ style_class: 'modal-dialog-button', button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, @@ -86,7 +130,7 @@ const AuthPrompt = new Lang.Class({ label: _("Cancel") }); this.cancelButton.connect('clicked', Lang.bind(this, function() { - this.emit('cancel'); + this.cancel(); })); this._buttonBox.add(this.cancelButton, { expand: false, @@ -129,6 +173,67 @@ const AuthPrompt = new Lang.Class({ })); }, + _onAskQuestion: function(verifier, serviceName, question, passwordChar) { + if (this._preemptiveAnswer) { + this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer); + this._preemptiveAnswer = null; + return; + } + + if (this._queryingService) + this.clear(); + + this._queryingService = serviceName; + this.setPasswordChar(passwordChar); + this.setQuestion(question); + + if (this.verifyingUser) + this.cancelButton.show(); + else + this.cancelButton.hide(); + + if (passwordChar) { + if (this._mode == AuthPromptMode.UNLOCK_ONLY) + this.nextButton.label = _("Unlock"); + else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN) + this.nextButton.label = C_("button", "Sign In"); + } else { + this.nextButton.label = _("Next"); + } + + this.updateSensitivity(true); + this.emit('prompted'); + }, + + _onShowMessage: function(userVerifier, message, styleClass) { + this.setMessage(message, styleClass); + }, + + _onVerificationFailed: function() { + this.clear(); + + this.updateSensitivity(true); + this.setActorInDefaultButtonWell(null); + this.userVerified = false; + }, + + _onVerificationComplete: function() { + this.userVerified = true; + }, + + _onReset: function() { + if (!this.userVerified) + this.reset(); + }, + + _onShowLoginHint: function(verifier, message) { + this.setHint(message); + }, + + _onHideLoginHint: function() { + this.setHint(null); + }, + addActorToDefaultButtonWell: function(actor) { this._defaultButtonWell.add_child(actor); @@ -278,9 +383,16 @@ const AuthPrompt = new Lang.Class({ }, reset: function() { + this.verifyingUser = false; + this.userVerified = false; + this._queryingService = null; + this.clear(); this._message.opacity = 0; this.setUser(null); this.stopSpinning(); + this.setHint(null); + + this.emit('reset'); }, addCharacter: function(unichar) { @@ -289,6 +401,40 @@ const AuthPrompt = new Lang.Class({ this._entry.grab_key_focus(); this._entry.clutter_text.insert_unichar(unichar); + }, + + begin: function(params) { + params = Params.parse(params, { userName: null, + hold: null }); + + this.updateSensitivity(false); + + let hold = params.hold; + if (!hold) + hold = new Batch.Hold(); + + this._userVerifier.begin(params.userName, hold); + this.verifyingUser = true; + }, + + finish: function(onComplete) { + if (!this._userVerifier.hasPendingMessages) { + onComplete(); + return; + } + + let signalId = this._userVerifier.connect('no-more-messages', + Lang.bind(this, function() { + this._userVerifier.disconnect(signalId); + onComplete(); + })); + }, + + cancel: function() { + if (this.verifyingUser) + this._userVerifier.cancel(); + + this.reset(); } }); Signals.addSignalMethods(AuthPrompt.prototype); diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js index 63460651a..46478aa2d 100644 --- a/js/gdm/loginDialog.js +++ b/js/gdm/loginDialog.js @@ -401,10 +401,10 @@ const LoginDialog = new Lang.Class({ parentActor.add_child(this.actor); this._userManager = AccountsService.UserManager.get_default() - this._greeterClient = new Gdm.Client(); + let gdmClient = new Gdm.Client(); if (GLib.getenv('GDM_GREETER_TEST') != '1') { - this._greeter = this._greeterClient.get_greeter_sync(null); + this._greeter = gdmClient.get_greeter_sync(null); this._greeter.connect('default-session-name-changed', Lang.bind(this, this._onDefaultSessionChanged)); @@ -415,15 +415,6 @@ const LoginDialog = new Lang.Class({ Lang.bind(this, this._onTimedLoginRequested)); } - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient); - this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._verificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._reset)); - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - this._verifyingUser = false; - this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA }); this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY, @@ -458,12 +449,10 @@ const LoginDialog = new Lang.Class({ x_fill: true, y_fill: true }); - this._authPrompt = new AuthPrompt.AuthPrompt(); + this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOGIN); + this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted)); + this._authPrompt.connect('reset', Lang.bind(this, this._reset)); this._authPrompt.hide(); - this._authPrompt.connect('cancel', - Lang.bind(this, function() { - this.cancel(); - })); this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor, align_axis: Clutter.AlignAxis.BOTH, @@ -540,7 +529,7 @@ const LoginDialog = new Lang.Class({ if (disableUserList != this._disableUserList) { this._disableUserList = disableUserList; - if (!this._verifyingUser) + if (!this._authPrompt.verifyingUser) this._reset(); } }, @@ -575,14 +564,24 @@ const LoginDialog = new Lang.Class({ this._updateLogoTexture(this._textureCache, this._logoFileUri); }, - _reset: function() { - this._userVerifier.clear(); + _onPrompted: function() { + this._sessionMenuButton.updateSensitivity(true); - this._updateSensitivity(true); - this._authPrompt.reset(); + if (this._shouldShowSessionMenuButton()) + this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor); + + this._authPrompt.cancelButton.show(); + + this._showPrompt(); + }, + + _reset: function() { + if (this._authPrompt.verifyingUser) + return; + + this._sessionMenuButton.updateSensitivity(true); this._user = null; - this._verifyingUser = false; if (this._disableUserList) this._hideUserListAndLogIn(); @@ -590,38 +589,12 @@ const LoginDialog = new Lang.Class({ this._showUserList(); }, - _verificationFailed: function() { - this._authPrompt.clear(); - - this._updateSensitivity(true); - this._authPrompt.setActorInDefaultButtonWell(null); - }, - _onDefaultSessionChanged: function(client, sessionId) { this._sessionMenuButton.setActiveSession(sessionId); }, - _showMessage: function(userVerifier, message, styleClass) { - this._authPrompt.setMessage(message, styleClass); - }, - - _showLoginHint: function(verifier, message) { - this._authPrompt.setHint(message); - }, - - _hideLoginHint: function() { - this._authPrompt.setHint(null); - }, - - cancel: function() { - if (this._verifyingUser) - this._userVerifier.cancel(); - else - this._reset(); - }, - _shouldShowSessionMenuButton: function() { - if (this._verifyingUser) + if (this._authPrompt.verifyingUser) return true; if (!this._user) @@ -633,75 +606,15 @@ const LoginDialog = new Lang.Class({ return true; }, - _showPrompt: function(forSecret) { + _showPrompt: function() { + if (this._authPrompt.actor.visible) + return; this._authPrompt.actor.opacity = 0; this._authPrompt.actor.show(); Tweener.addTween(this._authPrompt.actor, { opacity: 255, time: _FADE_ANIMATION_TIME, transition: 'easeOutQuad' }); - - let hold = new Batch.Hold(); - let tasks = [function() { - this._preparePrompt(forSecret, hold); - }, - - hold]; - - let batch = new Batch.ConcurrentBatch(this, tasks); - - return batch.run(); - }, - - _preparePrompt: function(forSecret, hold) { - if (!this._disableUserList || this._verifyingUser) { - this._authPrompt.cancelButton.show(); - } else { - this._authPrompt.cancelButton.hide(); - } - - if (forSecret) { - this._authPrompt.nextButton.label = C_("button", "Sign In"); - } else { - this._authPrompt.nextButton.label = _("Next"); - } - - let signalId = this._authPrompt.connect('next', Lang.bind(this, function() { - this._authPrompt.disconnect(signalId); - hold.release(); - })); - }, - - _updateSensitivity: function(sensitive) { - this._sessionMenuButton.updateSensitivity(sensitive); - this._authPrompt.updateSensitivity(sensitive); - }, - - _askQuestion: function(verifier, serviceName, question, passwordChar) { - this._authPrompt.setPasswordChar(passwordChar); - this._authPrompt.setQuestion(question); - - this._updateSensitivity(true); - - if (this._shouldShowSessionMenuButton()) - this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor); - else - this._authPrompt.setActorInDefaultButtonWell(null); - - let tasks = [function() { - return this._showPrompt(!!passwordChar); - }, - - function() { - let text = this._authPrompt.getAnswer(); - - this._updateSensitivity(false); - this._authPrompt.startSpinning(); - this._userVerifier.answerQuery(serviceName, text); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); }, _showRealmLoginHint: function(realmManager, hint) { @@ -714,7 +627,7 @@ const LoginDialog = new Lang.Class({ // Translators: this message is shown below the username entry field // to clue the user in on how to login to the local network realm - this._showLoginHint(null, _("(e.g., user or %s)").format(hint)); + this._authPrompt.setHint(_("(e.g., user or %s)").format(hint)); }, _askForUsernameAndLogIn: function() { @@ -722,25 +635,24 @@ const LoginDialog = new Lang.Class({ this._authPrompt.setQuestion(_("Username: ")); let realmManager = new Realmd.Manager(); - let signalId = realmManager.connect('login-format-changed', - Lang.bind(this, this._showRealmLoginHint)); + let realmSignalId = realmManager.connect('login-format-changed', + Lang.bind(this, this._showRealmLoginHint)); this._showRealmLoginHint(realmManager.loginFormat); - let tasks = [this._showPrompt, + let nextSignalId = this._authPrompt.connect('next', + Lang.bind(this, function() { + this._authPrompt.disconnect(nextSignalId); + this._authPrompt.updateSensitivity(false); + let answer = this._authPrompt.getAnswer(); + this._authPrompt.clear(); + this._authPrompt.startSpinning(); + this._authPrompt.begin({ userName: answer }); - function() { - let userName = this._authPrompt.getAnswer(); - this._authPrompt._entry.reactive = false; - return this._beginVerificationForUser(userName); - }, - - function() { - realmManager.disconnect(signalId) - realmManager.release(); - }]; - - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); + realmManager.disconnect(realmSignalId) + realmManager.release(); + })); + this._authPrompt.cancelButton.hide(); + this._showPrompt(); }, _startSession: function(serviceName) { @@ -767,15 +679,9 @@ const LoginDialog = new Lang.Class({ }, _onSessionOpened: function(client, serviceName) { - if (!this._userVerifier.hasPendingMessages) { + this._authPrompt.finish(Lang.bind(this, function() { this._startSession(serviceName); - } else { - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - this._startSession(serviceName); - })); - } + })); }, _waitForItemForUser: function(userName) { @@ -922,23 +828,15 @@ const LoginDialog = new Lang.Class({ this._userList.actor.grab_key_focus(); }, - _beginVerificationForUser: function(userName) { - let hold = new Batch.Hold(); - - this._userVerifier.begin(userName, hold); - this._verifyingUser = true; - return hold; - }, - _beginVerificationForItem: function(item) { this._authPrompt.setUser(item.user); - let tasks = [function() { - let userName = item.user.get_user_name(); - return this._beginVerificationForUser(userName); - }]; - let batch = new Batch.ConsecutiveBatch(this, tasks); - return batch.run(); + let userName = item.user.get_user_name(); + let hold = new Batch.Hold(); + + this._authPrompt.begin({ userName: userName, + hold: hold }); + return hold; }, _onUserListActivated: function(activatedItem) { diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js index 86ac19f13..1fc55eb70 100644 --- a/js/ui/unlockDialog.js +++ b/js/ui/unlockDialog.js @@ -42,33 +42,17 @@ const UnlockDialog = new Lang.Class({ this._userName = GLib.get_user_name(); this._user = this._userManager.get_user(this._userName); - this._firstQuestion = true; - - this._greeterClient = new Gdm.Client(); - this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true }); - this._userVerified = false; - - this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion)); - this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage)); - this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete)); - this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed)); - this._userVerifier.connect('reset', Lang.bind(this, this._onReset)); - - this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint)); - this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint)); - this._promptBox = new St.BoxLayout({ vertical: true }); this.actor.add_child(this._promptBox); this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor, align_axis: Clutter.AlignAxis.BOTH, factor: 0.5 })); - this._authPrompt = new AuthPrompt.AuthPrompt(); + this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY); + this._authPrompt.connect('reset', Lang.bind(this, this._onReset)); this._authPrompt.setUser(this._user); this._authPrompt.setPasswordChar('\u25cf'); this._authPrompt.nextButton.label = _("Unlock"); - this._authPrompt.connect('cancel', Lang.bind(this, this._escape)); - this._authPrompt.connect('next', Lang.bind(this, this._doUnlock)); this._promptBox.add_child(this._authPrompt.actor); @@ -90,11 +74,9 @@ const UnlockDialog = new Lang.Class({ this._otherUserButton = null; } + this._authPrompt.begin({ userName: this._userName }); this._updateSensitivity(true); - let batch = new Batch.Hold(); - this._userVerifier.begin(this._userName, batch); - Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic'); this._idleMonitor = new GnomeDesktop.IdleMonitor(); @@ -110,88 +92,13 @@ const UnlockDialog = new Lang.Class({ } }, - _showMessage: function(userVerifier, message, styleClass) { - this._authPrompt.setMessage(message, styleClass); - }, - - _onAskQuestion: function(verifier, serviceName, question, passwordChar) { - if (this._firstQuestion && this._firstQuestionAnswer) { - this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer); - this._firstQuestionAnswer = null; - this._firstQuestion = false; - return; - } - - if (!this._firstQuestion) - this._promptEntry.text = ''; - else - this._firstQuestion = false; - - this._authPrompt.setPasswordChar(passwordChar); - this._authPrompt.setQuestion(question); - - this._currentQuery = serviceName; - - this._updateSensitivity(true); - this._authPrompt.stopSpinning(); - }, - - _showLoginHint: function(verifier, message) { - this._authPrompt.setHint(message); - }, - - _hideLoginHint: function() { - this._authPrompt.setHint(null); - }, - - _doUnlock: function() { - if (this._firstQuestion) { - // we haven't received a query yet, so stash the answer - // and make ourself non-reactive - // the actual reply to GDM will be sent as soon as asked - this._firstQuestionAnswer = this._promptEntry.text; - this._updateSensitivity(false); - this._authPrompt.startSpinning(); - return; - } - - if (!this._currentQuery) - return; - - let query = this._currentQuery; - this._currentQuery = null; - - this._updateSensitivity(false); - this._authPrompt.startSpinning(); - - this._userVerifier.answerQuery(query, this._authPrompt.getAnswer()); - }, - - _onVerificationComplete: function() { - this._userVerified = true; - }, - _onReset: function() { - if (!this._userVerified) { - this._userVerifier.clear(); - this.emit('failed'); - } - }, - - _onVerificationFailed: function() { - this._currentQuery = null; - this._firstQuestion = true; - this._userVerified = false; - - this._authPrompt.clear(); - - this._updateSensitivity(false); - this._authPrompt.stopSpinning(); + this.emit('failed'); }, _escape: function() { if (this.allowCancel) { - this._userVerifier.cancel(); + this._authPrompt.cancel(); this.emit('failed'); } }, @@ -199,12 +106,11 @@ const UnlockDialog = new Lang.Class({ _otherUserClicked: function(button, event) { Gdm.goto_login_session_sync(null); - this._userVerifier.cancel(); - this.emit('failed'); + this._authPrompt.cancel(); }, destroy: function() { - this._userVerifier.clear(); + this.popModal(); this.actor.destroy(); if (this._idleWatchId) { @@ -214,7 +120,7 @@ const UnlockDialog = new Lang.Class({ }, cancel: function() { - this._userVerifier.cancel(null); + this._authPrompt.cancel(); this.destroy(); }, @@ -224,16 +130,7 @@ const UnlockDialog = new Lang.Class({ }, finish: function(onComplete) { - if (!this._userVerifier.hasPendingMessages) { - onComplete(); - return; - } - - let signalId = this._userVerifier.connect('no-more-messages', - Lang.bind(this, function() { - this._userVerifier.disconnect(signalId); - onComplete(); - })); + this._authPrompt.finish(onComplete); }, open: function(timestamp) {