Split some common code out of gdm/loginDialog
This will be reused by session unlocking. https://bugzilla.gnome.org/show_bug.cgi?id=619955
This commit is contained in:
parent
4e6fa56c87
commit
46db9edacc
@ -22,6 +22,7 @@ nobase_dist_js_DATA = \
|
|||||||
gdm/loginDialog.js \
|
gdm/loginDialog.js \
|
||||||
gdm/powerMenu.js \
|
gdm/powerMenu.js \
|
||||||
gdm/systemd.js \
|
gdm/systemd.js \
|
||||||
|
gdm/util.js \
|
||||||
extensionPrefs/main.js \
|
extensionPrefs/main.js \
|
||||||
misc/config.js \
|
misc/config.js \
|
||||||
misc/extensionUtils.js \
|
misc/extensionUtils.js \
|
||||||
|
@ -34,81 +34,19 @@ const Gdm = imports.gi.Gdm;
|
|||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
const Fprint = imports.gdm.fingerprint;
|
const Fprint = imports.gdm.fingerprint;
|
||||||
|
const GdmUtil = imports.gdm.util;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const _PASSWORD_SERVICE_NAME = 'gdm-password';
|
|
||||||
const _FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
|
||||||
const _FADE_ANIMATION_TIME = 0.16;
|
|
||||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||||
const _SCROLL_ANIMATION_TIME = 2.0;
|
const _SCROLL_ANIMATION_TIME = 2.0;
|
||||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||||
const _LOGO_ICON_NAME_SIZE = 48;
|
const _LOGO_ICON_NAME_SIZE = 48;
|
||||||
|
|
||||||
const _LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
|
||||||
const _FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
|
||||||
const _BANNER_MESSAGE_KEY = 'banner-message-enable';
|
|
||||||
const _BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
|
||||||
|
|
||||||
const _LOGO_KEY = 'logo';
|
|
||||||
|
|
||||||
let _loginDialog = null;
|
let _loginDialog = null;
|
||||||
|
|
||||||
function _fadeInActor(actor) {
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
|
|
||||||
if (actor.opacity == 255 && actor.visible)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
actor.show();
|
|
||||||
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
|
||||||
|
|
||||||
actor.opacity = 0;
|
|
||||||
actor.set_height(0);
|
|
||||||
Tweener.addTween(actor,
|
|
||||||
{ opacity: 255,
|
|
||||||
height: naturalHeight,
|
|
||||||
time: _FADE_ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
actor.set_height(-1);
|
|
||||||
hold.release();
|
|
||||||
},
|
|
||||||
onCompleteScope: this
|
|
||||||
});
|
|
||||||
return hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _fadeOutActor(actor) {
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
|
|
||||||
if (!actor.visible) {
|
|
||||||
actor.opacity = 0;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actor.opacity == 0) {
|
|
||||||
actor.hide();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tweener.addTween(actor,
|
|
||||||
{ opacity: 0,
|
|
||||||
height: 0,
|
|
||||||
time: _FADE_ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: function() {
|
|
||||||
actor.hide();
|
|
||||||
actor.set_height(-1);
|
|
||||||
hold.release();
|
|
||||||
},
|
|
||||||
onCompleteScope: this
|
|
||||||
});
|
|
||||||
return hold;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _smoothlyResizeActor(actor, width, height) {
|
function _smoothlyResizeActor(actor, width, height) {
|
||||||
let finalWidth;
|
let finalWidth;
|
||||||
let finalHeight;
|
let finalHeight;
|
||||||
@ -247,11 +185,11 @@ const UserListItem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
fadeOutName: function() {
|
fadeOutName: function() {
|
||||||
return _fadeOutActor(this._nameLabel);
|
return GdmUtil.fadeOutActor(this._nameLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
fadeInName: function() {
|
fadeInName: function() {
|
||||||
return _fadeInActor(this._nameLabel);
|
return GdmUtil.fadeInActor(this._nameLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
showFocusAnimation: function(time) {
|
showFocusAnimation: function(time) {
|
||||||
@ -304,7 +242,7 @@ const UserList = new Lang.Class({
|
|||||||
|
|
||||||
_showItem: function(item) {
|
_showItem: function(item) {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return _fadeInActor(item.actor);
|
return GdmUtil.fadeInActor(item.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -365,13 +303,13 @@ const UserList = new Lang.Class({
|
|||||||
item._focusBin.scale_x = 0.;
|
item._focusBin.scale_x = 0.;
|
||||||
if (item != exception)
|
if (item != exception)
|
||||||
tasks.push(function() {
|
tasks.push(function() {
|
||||||
return _fadeOutActor(item.actor);
|
return GdmUtil.fadeOutActor(item.actor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
return _fadeOutActor(this.actor.vscroll);
|
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks)
|
new Batch.ConcurrentBatch(this, tasks)
|
||||||
@ -438,7 +376,7 @@ const UserList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return _fadeInActor(this.actor.vscroll);
|
return GdmUtil.fadeInActor(this.actor.vscroll);
|
||||||
}]);
|
}]);
|
||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
@ -728,15 +666,21 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._greeter.connect('timed-login-requested',
|
this._greeter.connect('timed-login-requested',
|
||||||
Lang.bind(this, this._onTimedLoginRequested));
|
Lang.bind(this, this._onTimedLoginRequested));
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: _LOGIN_SCREEN_SCHEMA });
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
||||||
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
||||||
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
||||||
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._userVerifier.connect('show-fingerprint-prompt', Lang.bind(this, this._showFingerprintPrompt));
|
||||||
this._checkForFingerprintReader();
|
this._userVerifier.connect('hide-fingerprint-prompt', Lang.bind(this, this._hideFingerprintPrompt));
|
||||||
this._settings.connect('changed::' + _LOGO_KEY,
|
|
||||||
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
|
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
||||||
Lang.bind(this, this._updateLogo));
|
Lang.bind(this, this._updateLogo));
|
||||||
this._settings.connect('changed::' + _BANNER_MESSAGE_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
this._settings.connect('changed::' + _BANNER_MESSAGE_TEXT_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
|
|
||||||
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
||||||
@ -850,22 +794,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_checkForFingerprintReader: function() {
|
|
||||||
this._haveFingerprintReader = false;
|
|
||||||
|
|
||||||
if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY))
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, Lang.bind(this,
|
|
||||||
function(device, error) {
|
|
||||||
if (!error && device)
|
|
||||||
this._haveFingerprintReader = true;
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateLogo: function() {
|
_updateLogo: function() {
|
||||||
this._logoBox.child = null;
|
this._logoBox.child = null;
|
||||||
let path = this._settings.get_string(_LOGO_KEY);
|
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
let file = Gio.file_new_for_path(path);
|
let file = Gio.file_new_for_path(path);
|
||||||
@ -878,8 +809,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateBanner: function() {
|
_updateBanner: function() {
|
||||||
let enabled = this._settings.get_boolean(_BANNER_MESSAGE_KEY);
|
let enabled = this._settings.get_boolean(GdmUtil.BANNER_MESSAGE_KEY);
|
||||||
let text = this._settings.get_string(_BANNER_MESSAGE_TEXT_KEY);
|
let text = this._settings.get_string(GdmUtil.BANNER_MESSAGE_TEXT_KEY);
|
||||||
|
|
||||||
if (enabled && text) {
|
if (enabled && text) {
|
||||||
this._bannerLabel.set_text(text);
|
this._bannerLabel.set_text(text);
|
||||||
@ -890,10 +821,6 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function(client, serviceName) {
|
_onReset: function(client, serviceName) {
|
||||||
this._userVerifier = null;
|
|
||||||
|
|
||||||
this._checkForFingerprintReader();
|
|
||||||
|
|
||||||
let tasks = [this._hidePrompt,
|
let tasks = [this._hidePrompt,
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||||
@ -923,43 +850,25 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._sessionList.setActiveSession(sessionId);
|
this._sessionList.setActiveSession(sessionId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInfo: function(client, serviceName, info) {
|
_showFingerprintPrompt: function() {
|
||||||
// We don't display fingerprint messages, because they
|
GdmUtil.fadeInActor(this._promptFingerprintMessage);
|
||||||
// have words like UPEK in them. Instead we use the messages
|
|
||||||
// as a cue to display our own message.
|
|
||||||
if (serviceName == _FINGERPRINT_SERVICE_NAME &&
|
|
||||||
this._haveFingerprintReader &&
|
|
||||||
(!this._promptFingerprintMessage.visible ||
|
|
||||||
this._promptFingerprintMessage.opacity != 255)) {
|
|
||||||
|
|
||||||
_fadeInActor(this._promptFingerprintMessage);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
Main.notifyError(info);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onProblem: function(client, serviceName, problem) {
|
_hideFingerprintPrompt: function() {
|
||||||
// we don't want to show auth failed messages to
|
GdmUtil.fadeOutActor(this._promptFingerprintMessage);
|
||||||
// users who haven't enrolled their fingerprint.
|
}
|
||||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
Main.notifyError(problem);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCancel: function(client) {
|
_onCancel: function() {
|
||||||
this._userVerifier.call_cancel_sync(null);
|
this._userVerifier.cancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInPrompt: function() {
|
_fadeInPrompt: function() {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return _fadeInActor(this._promptLabel);
|
return GdmUtil.fadeInActor(this._promptLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return _fadeInActor(this._promptEntry);
|
return GdmUtil.fadeInActor(this._promptEntry);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -970,14 +879,14 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return _fadeInActor(this._promptBox);
|
return GdmUtil.fadeInActor(this._promptBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
if (this._user && this._user.is_logged_in())
|
if (this._user && this._user.is_logged_in())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return _fadeInActor(this._sessionList.actor);
|
return GdmUtil.fadeInActor(this._sessionList.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -1034,7 +943,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this.setButtons([]);
|
this.setButtons([]);
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return _fadeOutActor(this._promptBox);
|
return GdmUtil.fadeOutActor(this._promptBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@ -1049,40 +958,24 @@ const LoginDialog = new Lang.Class({
|
|||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
_askQuestion: function(serviceName, question) {
|
_askQuestion: function(verifier, serviceName, question, passwordChar) {
|
||||||
this._promptLabel.set_text(question);
|
this._promptLabel.set_text(question);
|
||||||
|
|
||||||
|
this._promptEntry.set_text('');
|
||||||
|
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
||||||
|
|
||||||
let tasks = [this._showPrompt,
|
let tasks = [this._showPrompt,
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let _text = this._promptEntry.get_text();
|
let _text = this._promptEntry.get_text();
|
||||||
this._promptEntry.reactive = false;
|
this._promptEntry.reactive = false;
|
||||||
this._promptEntry.add_style_pseudo_class('insensitive');
|
this._promptEntry.add_style_pseudo_class('insensitive');
|
||||||
this._userVerifier.call_answer_query_sync(serviceName, _text, null);
|
this._userVerifier.answerQuery(serviceName, _text);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
|
||||||
// We only expect questions to come from the main auth service
|
|
||||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._promptEntry.set_text('');
|
|
||||||
this._promptEntry.clutter_text.set_password_char('');
|
|
||||||
this._askQuestion(serviceName, question);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
|
||||||
// We only expect secret requests to come from the main auth service
|
|
||||||
if (serviceName != _PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._promptEntry.set_text('');
|
|
||||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
|
||||||
this._askQuestion(serviceName, secretQuestion);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onSessionOpened: function(client, serviceName) {
|
_onSessionOpened: function(client, serviceName) {
|
||||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||||
@ -1210,15 +1103,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onConversationStopped: function(client, serviceName) {
|
_onVerificationFailed: function() {
|
||||||
// if the password service fails, then cancel everything.
|
this._userVerifier.cancel();
|
||||||
// But if, e.g., fingerprint fails, still give
|
|
||||||
// password authentication a chance to succeed
|
|
||||||
if (serviceName == _PASSWORD_SERVICE_NAME) {
|
|
||||||
this._userVerifier.call_cancel_sync(null);
|
|
||||||
} else if (serviceName == _FINGERPRINT_SERVICE_NAME) {
|
|
||||||
_fadeOutActor(this._promptFingerprintMessage);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNotListedClicked: function(user) {
|
_onNotListedClicked: function(user) {
|
||||||
@ -1241,13 +1127,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
function() {
|
function() {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
this._userVerifier.call_begin_verification(_PASSWORD_SERVICE_NAME,
|
this._userVerifier.begin(null, hold);
|
||||||
null,
|
|
||||||
Lang.bind(this, function (userVerifier, result) {
|
|
||||||
this._userVerifier.call_begin_verification_finish (result);
|
|
||||||
hold.release();
|
|
||||||
}));
|
|
||||||
|
|
||||||
return hold;
|
return hold;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -1256,127 +1136,42 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_fadeInLogo: function() {
|
_fadeInLogo: function() {
|
||||||
return _fadeInActor(this._logoBox);
|
return GdmUtil.fadeInActor(this._logoBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutLogo: function() {
|
_fadeOutLogo: function() {
|
||||||
return _fadeOutActor(this._logoBox);
|
return GdmUtil.fadeOutActor(this._logoBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInBanner: function() {
|
_fadeInBanner: function() {
|
||||||
return _fadeInActor(this._bannerLabel);
|
return GdmUtil.fadeInActor(this._bannerLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutBanner: function() {
|
_fadeOutBanner: function() {
|
||||||
return _fadeOutActor(this._bannerLabel);
|
return GdmUtil.fadeOutActor(this._bannerLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInTitleLabel: function() {
|
_fadeInTitleLabel: function() {
|
||||||
return _fadeInActor(this._titleLabel);
|
return GdmUtil.fadeInActor(this._titleLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutTitleLabel: function() {
|
_fadeOutTitleLabel: function() {
|
||||||
return _fadeOutActor(this._titleLabel);
|
return GdmUtil.fadeOutActor(this._titleLabel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInNotListedButton: function() {
|
_fadeInNotListedButton: function() {
|
||||||
return _fadeInActor(this._notListedButton);
|
return GdmUtil.fadeInActor(this._notListedButton);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutNotListedButton: function() {
|
_fadeOutNotListedButton: function() {
|
||||||
return _fadeOutActor(this._notListedButton);
|
return GdmUtil.fadeOutActor(this._notListedButton);
|
||||||
},
|
|
||||||
|
|
||||||
_getUserVerifier: function(userName) {
|
|
||||||
let hold = new Batch.Hold();
|
|
||||||
|
|
||||||
this._userVerifier = null;
|
|
||||||
|
|
||||||
// If possible, reauthenticate an already running session,
|
|
||||||
// so any session specific credentials get updated appropriately
|
|
||||||
this._greeterClient.open_reauthentication_channel(userName,
|
|
||||||
null,
|
|
||||||
Lang.bind(this, function(client, result) {
|
|
||||||
try {
|
|
||||||
this._userVerifier = this._greeterClient.open_reauthentication_channel_finish(result);
|
|
||||||
hold.release();
|
|
||||||
} catch (e) {
|
|
||||||
// If there's no session running, or it otherwise fails, then fall back
|
|
||||||
// to performing verification from this login session
|
|
||||||
this._greeterClient.get_user_verifier(null,
|
|
||||||
Lang.bind(this, function(client, result) {
|
|
||||||
this._userVerifier = this._greeterClient.get_user_verifier_finish(result);
|
|
||||||
hold.release();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
hold.connect('release', Lang.bind(this, function() {
|
|
||||||
if (this._userVerifier) {
|
|
||||||
let ids = [];
|
|
||||||
let id;
|
|
||||||
|
|
||||||
id = this._userVerifier.connect('info',
|
|
||||||
Lang.bind(this, this._onInfo));
|
|
||||||
ids.push(id);
|
|
||||||
id = this._userVerifier.connect('problem',
|
|
||||||
Lang.bind(this, this._onProblem));
|
|
||||||
ids.push(id);
|
|
||||||
id = this._userVerifier.connect('info-query',
|
|
||||||
Lang.bind(this, this._onInfoQuery));
|
|
||||||
ids.push(id);
|
|
||||||
id = this._userVerifier.connect('secret-info-query',
|
|
||||||
Lang.bind(this, this._onSecretInfoQuery));
|
|
||||||
ids.push(id);
|
|
||||||
id = this._userVerifier.connect('conversation-stopped',
|
|
||||||
Lang.bind(this, this._onConversationStopped));
|
|
||||||
ids.push(id);
|
|
||||||
id = this._userVerifier.connect('reset',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
for (let i = 0; i < ids.length; i++)
|
|
||||||
this._userVerifier.disconnect(ids[i]);
|
|
||||||
|
|
||||||
this._onReset();
|
|
||||||
}));
|
|
||||||
ids.push(id);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return hold;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_beginVerificationForUser: function(userName) {
|
_beginVerificationForUser: function(userName) {
|
||||||
let tasks = [function() {
|
let hold = new Batch.Hold();
|
||||||
let hold = new Batch.Hold();
|
|
||||||
this._userVerifier.call_begin_verification_for_user (_PASSWORD_SERVICE_NAME,
|
|
||||||
userName, null,
|
|
||||||
Lang.bind(this, function(userVerifier, result) {
|
|
||||||
this._userVerifier.call_begin_verification_for_user_finish (result);
|
|
||||||
hold.release();
|
|
||||||
}));
|
|
||||||
return hold;
|
|
||||||
},
|
|
||||||
|
|
||||||
function() {
|
this._userVerifier.begin(userName, hold);
|
||||||
let hold = new Batch.Hold();
|
return hold;
|
||||||
if (this._haveFingerprintReader) {
|
|
||||||
this._userVerifier.call_begin_verification_for_user (_FINGERPRINT_SERVICE_NAME,
|
|
||||||
userName, null,
|
|
||||||
Lang.bind(this, function(userVerifier, result) {
|
|
||||||
this._userVerifier.call_begin_verification_for_user_finish (result);
|
|
||||||
hold.release();
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
hold.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return hold;
|
|
||||||
}];
|
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, [this._getUserVerifier(userName),
|
|
||||||
new Batch.ConcurrentBatch(this, tasks)]);
|
|
||||||
|
|
||||||
return batch.run();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUserListActivated: function(activatedItem) {
|
_onUserListActivated: function(activatedItem) {
|
||||||
|
255
js/gdm/util.js
Normal file
255
js/gdm/util.js
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const Batch = imports.gdm.batch;
|
||||||
|
const Fprint = imports.gdm.fingerprint;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
|
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
|
const FADE_ANIMATION_TIME = 0.16;
|
||||||
|
|
||||||
|
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
|
|
||||||
|
const LOGO_KEY = 'logo';
|
||||||
|
|
||||||
|
function fadeInActor(actor) {
|
||||||
|
if (actor.opacity == 255 && actor.visible)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let hold = new Batch.Hold();
|
||||||
|
actor.show();
|
||||||
|
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
||||||
|
|
||||||
|
actor.opacity = 0;
|
||||||
|
actor.set_height(0);
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ opacity: 255,
|
||||||
|
height: naturalHeight,
|
||||||
|
time: FADE_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: function() {
|
||||||
|
this.set_height(-1);
|
||||||
|
hold.release();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fadeOutActor(actor) {
|
||||||
|
if (!actor.visible || actor.opacity == 0) {
|
||||||
|
actor.opacity = 0;
|
||||||
|
actor.hide();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hold = new Batch.Hold();
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ opacity: 0,
|
||||||
|
height: 0,
|
||||||
|
time: FADE_ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: function() {
|
||||||
|
this.hide();
|
||||||
|
this.set_height(-1);
|
||||||
|
hold.release();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShellUserVerifier = new Lang.Class({
|
||||||
|
Name: 'ShellUserVerifier',
|
||||||
|
|
||||||
|
_init: function(client) {
|
||||||
|
this._client = client;
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
|
|
||||||
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
|
this._checkForFingerprintReader();
|
||||||
|
},
|
||||||
|
|
||||||
|
begin: function(userName, hold) {
|
||||||
|
this._hold = hold;
|
||||||
|
this._userName = userName;
|
||||||
|
|
||||||
|
if (userName) {
|
||||||
|
// If possible, reauthenticate an already running session,
|
||||||
|
// so any session specific credentials get updated appropriately
|
||||||
|
this._client.open_reauthentication_channel(userName, this._cancellable,
|
||||||
|
Lang.bind(this, this._reauthenticationChannelOpened));
|
||||||
|
} else {
|
||||||
|
this._client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: function() {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
|
||||||
|
if (this._userVerifier)
|
||||||
|
this._userVerifier.call_cancel_sync(null);
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function() {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
|
||||||
|
if (this._userVerifier) {
|
||||||
|
this._userVerifier.run_dispose();
|
||||||
|
this._userVerifier = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
answerQuery: function(serviceName, answer) {
|
||||||
|
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkForFingerprintReader: function() {
|
||||||
|
this._haveFingerprintReader = false;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
|
||||||
|
function(device, error) {
|
||||||
|
if (!error && device)
|
||||||
|
this._haveFingerprintReader = true;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_reauthenticationChannelOpened: function(client, result) {
|
||||||
|
try {
|
||||||
|
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
||||||
|
this._connectSignals();
|
||||||
|
this._beginVerification();
|
||||||
|
|
||||||
|
this._hold.release();
|
||||||
|
} catch (e) {
|
||||||
|
// If there's no session running, or it otherwise fails, then fall back
|
||||||
|
// to performing verification from this login session
|
||||||
|
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_userVerifierGot: function(client, result) {
|
||||||
|
this._userVerifier = client.get_user_verifier_finish(result);
|
||||||
|
this._connectSignals();
|
||||||
|
this._beginVerification();
|
||||||
|
|
||||||
|
this._hold.release();
|
||||||
|
},
|
||||||
|
|
||||||
|
_connectSignals: function() {
|
||||||
|
this._userVerifier.connect('info', Lang.bind(this, this._onInfo));
|
||||||
|
this._userVerifier.connect('problem', Lang.bind(this, this._onProblem));
|
||||||
|
this._userVerifier.connect('info-query', Lang.bind(this, this._onInfoQuery));
|
||||||
|
this._userVerifier.connect('secret-info-query', Lang.bind(this, this._onSecretInfoQuery));
|
||||||
|
this._userVerifier.connect('conversation-stopped', Lang.bind(this, this._onConversationStopped));
|
||||||
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||||
|
},
|
||||||
|
|
||||||
|
_beginVerification: function() {
|
||||||
|
this._hold.acquire();
|
||||||
|
|
||||||
|
if (this._userName) {
|
||||||
|
this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME,
|
||||||
|
this._userName,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, function(obj, result) {
|
||||||
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
|
this._hold.release();
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (this._haveFingerprintReader) {
|
||||||
|
this._hold.acquire();
|
||||||
|
|
||||||
|
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
||||||
|
this._userName,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, function(obj, result) {
|
||||||
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
|
this._hold.release();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, function(obj, result) {
|
||||||
|
obj.call_begin_verification_finish(result);
|
||||||
|
this._hold.release();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onInfo: function(client, serviceName, info) {
|
||||||
|
// We don't display fingerprint messages, because they
|
||||||
|
// have words like UPEK in them. Instead we use the messages
|
||||||
|
// as a cue to display our own message.
|
||||||
|
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
||||||
|
this._haveFingerprintReader) {
|
||||||
|
this.emit('show-fingerprint-prompt');
|
||||||
|
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
|
Main.notifyError(info);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onProblem: function(client, serviceName, problem) {
|
||||||
|
// we don't want to show auth failed messages to
|
||||||
|
// users who haven't enrolled their fingerprint.
|
||||||
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
Main.notifyError(problem);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onInfoQuery: function(client, serviceName, question) {
|
||||||
|
// We only expect questions to come from the main auth service
|
||||||
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.emit('ask-question', serviceName, question, '');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||||
|
// We only expect secret requests to come from the main auth service
|
||||||
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onReset: function() {
|
||||||
|
this._userVerifier.run_dispose();
|
||||||
|
this._userVerifier = null;
|
||||||
|
|
||||||
|
this._checkForFingerprintReader();
|
||||||
|
|
||||||
|
this.emit('reset');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onVerificationComplete: function() {
|
||||||
|
this.emit('verification-complete');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onConversationStopped: function(client, serviceName) {
|
||||||
|
// if the password service fails, then cancel everything.
|
||||||
|
// But if, e.g., fingerprint fails, still give
|
||||||
|
// password authentication a chance to succeed
|
||||||
|
if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
|
this.emit('verification-failed');
|
||||||
|
} else if (serviceName == FINGERPRINT_SERVICE_NAME) {
|
||||||
|
this.emit('hide-fingerprint-prompt');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ShellUserVerifier.prototype);
|
Loading…
x
Reference in New Issue
Block a user