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:
Ray Strode 2011-09-06 16:17:08 -04:00
parent d3e35028ca
commit 43f1d0578b
4 changed files with 99 additions and 1 deletions

View File

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

View File

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

View File

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