authPrompt: move unlock and login user verifier code here

There's quite a bit of duplicated code between the login dialog
and the unlock dialog dealing with the various signals from the
ShellUserVerifier.

This commit moves that duplicated code into the AuthPrompt.

https://bugzilla.gnome.org/show_bug.cgi?id=704707
This commit is contained in:
Ray Strode 2013-07-22 11:07:35 -04:00
parent d30cb2d4d9
commit 7e7295f259
3 changed files with 207 additions and 266 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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) {