gdm: add fingerprint support
This commit adds the ability to log in with a fingerprint instead of a password (assuming the user is enrolled and fingerprint isn't disabled via gsettings) https://bugzilla.gnome.org/show_bug.cgi?id=657823
This commit is contained in:
parent
d3e35028ca
commit
43f1d0578b
@ -30,6 +30,10 @@
|
|||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-dialog-prompt-fingerprint-message {
|
||||||
|
font-size: 10.5pt;
|
||||||
|
}
|
||||||
|
|
||||||
.login-dialog-user-list-view {
|
.login-dialog-user-list-view {
|
||||||
-st-vfade-offset: 1em;
|
-st-vfade-offset: 1em;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ jsdir = $(pkgdatadir)/js
|
|||||||
nobase_dist_js_DATA = \
|
nobase_dist_js_DATA = \
|
||||||
gdm/batch.js \
|
gdm/batch.js \
|
||||||
gdm/consoleKit.js \
|
gdm/consoleKit.js \
|
||||||
|
gdm/fingerprint.js \
|
||||||
gdm/loginDialog.js \
|
gdm/loginDialog.js \
|
||||||
gdm/powerMenu.js \
|
gdm/powerMenu.js \
|
||||||
misc/config.js \
|
misc/config.js \
|
||||||
|
26
js/gdm/fingerprint.js
Normal file
26
js/gdm/fingerprint.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||||
|
|
||||||
|
const DBus = imports.dbus;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const FprintManagerIface = {
|
||||||
|
name: 'net.reactivated.Fprint.Manager',
|
||||||
|
methods: [{ name: 'GetDefaultDevice',
|
||||||
|
inSignature: '',
|
||||||
|
outSignature: 'o' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
function FprintManager() {
|
||||||
|
this._init();
|
||||||
|
};
|
||||||
|
|
||||||
|
FprintManager.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
DBus.system.proxifyObject(this,
|
||||||
|
'net.reactivated.Fprint',
|
||||||
|
'/net/reactivated/Fprint/Manager');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DBus.proxifyPrototype(FprintManager.prototype, FprintManagerIface);
|
@ -33,17 +33,23 @@ const St = imports.gi.St;
|
|||||||
const GdmGreeter = imports.gi.GdmGreeter;
|
const GdmGreeter = imports.gi.GdmGreeter;
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
|
const DBus = imports.dbus;
|
||||||
|
const Fprint = imports.gdm.fingerprint;
|
||||||
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 _PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
|
const _FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
const _FADE_ANIMATION_TIME = 0.16;
|
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 _LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
|
const _FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
|
||||||
let _loginDialog = null;
|
let _loginDialog = null;
|
||||||
|
|
||||||
function _fadeInActor(actor) {
|
function _fadeInActor(actor) {
|
||||||
@ -761,6 +767,11 @@ LoginDialog.prototype = {
|
|||||||
this._greeterClient.connect('conversation-stopped',
|
this._greeterClient.connect('conversation-stopped',
|
||||||
Lang.bind(this, this._onConversationStopped));
|
Lang.bind(this, this._onConversationStopped));
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: _LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
|
this._startFingerprintConversationIfNeeded();
|
||||||
|
|
||||||
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
||||||
text: C_("title", "Sign In") });
|
text: C_("title", "Sign In") });
|
||||||
|
|
||||||
@ -805,6 +816,12 @@ LoginDialog.prototype = {
|
|||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
|
// translators: this message is shown below the password entry field
|
||||||
|
// to indicate the user can swipe their finger instead
|
||||||
|
this._promptFingerprintMessage = new St.Label({ text: _("(or swipe finger)"),
|
||||||
|
style_class: 'login-dialog-prompt-fingerprint-message' });
|
||||||
|
this._promptFingerprintMessage.hide();
|
||||||
|
this._promptBox.add(this._promptFingerprintMessage);
|
||||||
|
|
||||||
this._sessionList = new SessionList();
|
this._sessionList = new SessionList();
|
||||||
this._sessionList.connect('session-activated',
|
this._sessionList.connect('session-activated',
|
||||||
@ -852,10 +869,27 @@ LoginDialog.prototype = {
|
|||||||
this._onUserListActivated(item);
|
this._onUserListActivated(item);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_startFingerprintConversationIfNeeded: function() {
|
||||||
|
this._haveFingerprintReader = false;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(_FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._fprintManager.GetDefaultDeviceRemote(DBus.CALL_FLAG_START, Lang.bind(this,
|
||||||
|
function(device, error) {
|
||||||
|
if (!error && device)
|
||||||
|
this._haveFingerprintReader = true;
|
||||||
|
|
||||||
|
if (this._haveFingerprintReader)
|
||||||
|
this._greeterClient.call_start_conversation(_FINGERPRINT_SERVICE_NAME);
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function(client, serviceName) {
|
_onReset: function(client, serviceName) {
|
||||||
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
this._greeterClient.call_start_conversation(_PASSWORD_SERVICE_NAME);
|
||||||
|
this._startFingerprintConversationIfNeeded();
|
||||||
|
|
||||||
let tasks = [this._hidePrompt,
|
let tasks = [this._hidePrompt,
|
||||||
|
|
||||||
@ -885,10 +919,17 @@ LoginDialog.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onInfo: function(client, serviceName, info) {
|
_onInfo: function(client, serviceName, info) {
|
||||||
|
// we don't want fingerprint messages with the word UPEK in them
|
||||||
|
if (serviceName != _PASSWORD_SERVICE_NAME)
|
||||||
|
return;
|
||||||
Main.notifyError(info);
|
Main.notifyError(info);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onProblem: function(client, serviceName, problem) {
|
_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);
|
Main.notifyError(problem);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -905,6 +946,13 @@ LoginDialog.prototype = {
|
|||||||
return _fadeInActor(this._promptEntry);
|
return _fadeInActor(this._promptEntry);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function() {
|
||||||
|
if (!this._haveFingerprintReader)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return _fadeInActor(this._promptFingerprintMessage);
|
||||||
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return _fadeInActor(this._promptBox);
|
return _fadeInActor(this._promptBox);
|
||||||
},
|
},
|
||||||
@ -973,6 +1021,7 @@ LoginDialog.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
|
this._promptFingerprintMessage.hide();
|
||||||
this._promptEntry.set_text('');
|
this._promptEntry.set_text('');
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -996,12 +1045,20 @@ LoginDialog.prototype = {
|
|||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
_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.set_text('');
|
||||||
this._promptEntry.clutter_text.set_password_char('');
|
this._promptEntry.clutter_text.set_password_char('');
|
||||||
this._askQuestion(serviceName, question);
|
this._askQuestion(serviceName, question);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
_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.set_text('');
|
||||||
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||||
this._askQuestion(serviceName, secretQuestion);
|
this._askQuestion(serviceName, secretQuestion);
|
||||||
@ -1138,7 +1195,14 @@ LoginDialog.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onConversationStopped: function(client, serviceName) {
|
_onConversationStopped: function(client, serviceName) {
|
||||||
this._greeterClient.call_cancel();
|
// 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._greeterClient.call_cancel();
|
||||||
|
} else if (serviceName == _FINGERPRINT_SERVICE_NAME) {
|
||||||
|
_fadeOutActor(this._promptFingerprintMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNotListedClicked: function(user) {
|
_onNotListedClicked: function(user) {
|
||||||
@ -1210,6 +1274,9 @@ LoginDialog.prototype = {
|
|||||||
let userName = activatedItem.user.get_user_name();
|
let userName = activatedItem.user.get_user_name();
|
||||||
this._greeterClient.call_begin_verification_for_user(_PASSWORD_SERVICE_NAME,
|
this._greeterClient.call_begin_verification_for_user(_PASSWORD_SERVICE_NAME,
|
||||||
userName);
|
userName);
|
||||||
|
|
||||||
|
if (this._haveFingerprintReader)
|
||||||
|
this._greeterClient.call_begin_verification_for_user(_FINGERPRINT_SERVICE_NAME, userName);
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this._user = activatedItem.user;
|
this._user = activatedItem.user;
|
||||||
|
Loading…
Reference in New Issue
Block a user