Compare commits
16 Commits
citadel
...
wip/smartc
Author | SHA1 | Date | |
---|---|---|---|
|
d139adc25f | ||
|
0d151f8d94 | ||
|
e3fdc2858d | ||
|
05dcd8575c | ||
|
214440fde4 | ||
|
e3621e13ac | ||
|
df0aace025 | ||
|
023f4b31d9 | ||
|
16fba7bd5f | ||
|
ebce362c05 | ||
|
c4ca17d127 | ||
|
3455dd1e76 | ||
|
57abfab923 | ||
|
3a13e7484a | ||
|
a04895383a | ||
|
43357a1b69 |
@ -34,7 +34,9 @@ nobase_dist_js_DATA = \
|
|||||||
misc/jsParse.js \
|
misc/jsParse.js \
|
||||||
misc/loginManager.js \
|
misc/loginManager.js \
|
||||||
misc/modemManager.js \
|
misc/modemManager.js \
|
||||||
|
misc/objectManager.js \
|
||||||
misc/params.js \
|
misc/params.js \
|
||||||
|
misc/smartcardManager.js \
|
||||||
misc/util.js \
|
misc/util.js \
|
||||||
perf/core.js \
|
perf/core.js \
|
||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
|
@ -24,11 +24,23 @@ const AuthPromptMode = {
|
|||||||
UNLOCK_OR_LOG_IN: 1
|
UNLOCK_OR_LOG_IN: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AuthPromptStatus = {
|
||||||
|
NOT_VERIFYING: 0,
|
||||||
|
VERIFYING: 1,
|
||||||
|
VERIFICATION_FAILED: 2,
|
||||||
|
VERIFICATION_SUCCEEDED: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const BeginRequestType = {
|
||||||
|
PROVIDE_USERNAME: 0,
|
||||||
|
DONT_PROVIDE_USERNAME: 1
|
||||||
|
};
|
||||||
|
|
||||||
const AuthPrompt = new Lang.Class({
|
const AuthPrompt = new Lang.Class({
|
||||||
Name: 'AuthPrompt',
|
Name: 'AuthPrompt',
|
||||||
|
|
||||||
_init: function(gdmClient, mode) {
|
_init: function(gdmClient, mode) {
|
||||||
this.verifyingUser = false;
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
|
|
||||||
this._gdmClient = gdmClient;
|
this._gdmClient = gdmClient;
|
||||||
this._mode = mode;
|
this._mode = mode;
|
||||||
@ -48,6 +60,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
||||||
|
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
this.connect('next', Lang.bind(this, function() {
|
this.connect('next', Lang.bind(this, function() {
|
||||||
this.updateSensitivity(false);
|
this.updateSensitivity(false);
|
||||||
@ -123,6 +137,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
this._userVerifier.clear();
|
this._userVerifier.clear();
|
||||||
|
this._userVerifier.disconnectAll();
|
||||||
|
this._userVerifier = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_initButtons: function() {
|
_initButtons: function() {
|
||||||
@ -193,11 +209,6 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.setPasswordChar(passwordChar);
|
this.setPasswordChar(passwordChar);
|
||||||
this.setQuestion(question);
|
this.setQuestion(question);
|
||||||
|
|
||||||
if (this.verifyingUser)
|
|
||||||
this.cancelButton.show();
|
|
||||||
else
|
|
||||||
this.cancelButton.hide();
|
|
||||||
|
|
||||||
if (passwordChar) {
|
if (passwordChar) {
|
||||||
if (this._userVerifier.reauthenticating)
|
if (this._userVerifier.reauthenticating)
|
||||||
this.nextButton.label = _("Unlock");
|
this.nextButton.label = _("Unlock");
|
||||||
@ -211,8 +222,23 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.emit('prompted');
|
this.emit('prompted');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSmartcardStatusChanged: function() {
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
|
// Don't reset on smartcard insertion if we're already verifying
|
||||||
|
// and the smartcard is the main service
|
||||||
|
if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
|
||||||
|
this.verificationStatus == AuthPromptStatus.VERIFYING &&
|
||||||
|
this.smartcardDetected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
|
||||||
_onShowMessage: function(userVerifier, message, styleClass) {
|
_onShowMessage: function(userVerifier, message, styleClass) {
|
||||||
this.setMessage(message, styleClass);
|
this.setMessage(message, styleClass);
|
||||||
|
this.emit('prompted');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_onVerificationFailed: function() {
|
||||||
@ -220,16 +246,18 @@ const AuthPrompt = new Lang.Class({
|
|||||||
|
|
||||||
this.updateSensitivity(true);
|
this.updateSensitivity(true);
|
||||||
this.setActorInDefaultButtonWell(null);
|
this.setActorInDefaultButtonWell(null);
|
||||||
this.userVerified = false;
|
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationComplete: function() {
|
_onVerificationComplete: function() {
|
||||||
this.userVerified = true;
|
this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
if (!this.userVerified)
|
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) {
|
||||||
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
this.reset();
|
this.reset();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onShowLoginHint: function(verifier, message) {
|
_onShowLoginHint: function(verifier, message) {
|
||||||
@ -401,8 +429,12 @@ const AuthPrompt = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.verifyingUser = false;
|
let oldStatus = this.verificationStatus;
|
||||||
this.userVerified = false;
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
|
|
||||||
|
if (oldStatus == AuthPromptStatus.VERIFYING)
|
||||||
|
this._userVerifier.cancel();
|
||||||
|
|
||||||
this._queryingService = null;
|
this._queryingService = null;
|
||||||
this.clear();
|
this.clear();
|
||||||
this._message.opacity = 0;
|
this._message.opacity = 0;
|
||||||
@ -410,7 +442,25 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.stopSpinning();
|
this.stopSpinning();
|
||||||
this.setHint(null);
|
this.setHint(null);
|
||||||
|
|
||||||
this.emit('reset');
|
if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
|
||||||
|
this.emit('failed');
|
||||||
|
|
||||||
|
let beginRequestType;
|
||||||
|
|
||||||
|
if (this._mode == AuthPromptMode.UNLOCK_ONLY) {
|
||||||
|
// The user is constant at the unlock screen
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
} else if (this.smartcardDetected &&
|
||||||
|
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
||||||
|
// We don't need to know the username if the user preempted the login screen
|
||||||
|
// with a smartcard.
|
||||||
|
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
||||||
|
} else {
|
||||||
|
// In all other cases, we should get the username up front.
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('reset', beginRequestType);
|
||||||
},
|
},
|
||||||
|
|
||||||
addCharacter: function(unichar) {
|
addCharacter: function(unichar) {
|
||||||
@ -432,7 +482,7 @@ const AuthPrompt = new Lang.Class({
|
|||||||
hold = new Batch.Hold();
|
hold = new Batch.Hold();
|
||||||
|
|
||||||
this._userVerifier.begin(params.userName, hold);
|
this._userVerifier.begin(params.userName, hold);
|
||||||
this.verifyingUser = true;
|
this.verificationStatus = AuthPromptStatus.VERIFYING;
|
||||||
},
|
},
|
||||||
|
|
||||||
finish: function(onComplete) {
|
finish: function(onComplete) {
|
||||||
@ -449,10 +499,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
if (this.verifyingUser)
|
|
||||||
this._userVerifier.cancel();
|
|
||||||
|
|
||||||
this.reset();
|
this.reset();
|
||||||
|
this.emit('cancelled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(AuthPrompt.prototype);
|
Signals.addSignalMethods(AuthPrompt.prototype);
|
||||||
|
@ -451,7 +451,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
|
this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
|
||||||
this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
|
this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
|
||||||
this._authPrompt.connect('reset', Lang.bind(this, this._reset));
|
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._authPrompt.hide();
|
this._authPrompt.hide();
|
||||||
|
|
||||||
this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
|
this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
|
||||||
@ -475,7 +475,12 @@ const LoginDialog = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
|
||||||
this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAndLogIn));
|
this._notListedButton.connect('clicked',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
|
this._hideUserListAskForUsernameAndBeginVerification();
|
||||||
|
}));
|
||||||
|
|
||||||
this._notListedButton.hide();
|
this._notListedButton.hide();
|
||||||
|
|
||||||
this._userSelectionBox.add(this._notListedButton,
|
this._userSelectionBox.add(this._notListedButton,
|
||||||
@ -529,8 +534,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
if (disableUserList != this._disableUserList) {
|
if (disableUserList != this._disableUserList) {
|
||||||
this._disableUserList = disableUserList;
|
this._disableUserList = disableUserList;
|
||||||
|
|
||||||
if (!this._authPrompt.verifyingUser)
|
if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||||
this._reset();
|
this._authPrompt.reset();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -569,24 +574,25 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
if (this._shouldShowSessionMenuButton())
|
if (this._shouldShowSessionMenuButton())
|
||||||
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
|
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
|
||||||
|
|
||||||
this._authPrompt.cancelButton.show();
|
|
||||||
|
|
||||||
this._showPrompt();
|
this._showPrompt();
|
||||||
},
|
},
|
||||||
|
|
||||||
_reset: function() {
|
_onReset: function(authPrompt, beginRequest) {
|
||||||
if (this._authPrompt.verifyingUser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._sessionMenuButton.updateSensitivity(true);
|
this._sessionMenuButton.updateSensitivity(true);
|
||||||
|
|
||||||
this._user = null;
|
this._user = null;
|
||||||
|
|
||||||
if (this._disableUserList)
|
if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
|
||||||
this._hideUserListAndLogIn();
|
if (this._disableUserList) {
|
||||||
else
|
this._authPrompt.cancelButton.hide();
|
||||||
this._showUserList();
|
this._hideUserListAskForUsernameAndBeginVerification();
|
||||||
|
} else {
|
||||||
|
this._showUserList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._authPrompt.cancelButton.hide();
|
||||||
|
this._hideUserListAndBeginVerification();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDefaultSessionChanged: function(client, sessionId) {
|
_onDefaultSessionChanged: function(client, sessionId) {
|
||||||
@ -630,7 +636,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._authPrompt.setHint(_("(e.g., user or %s)").format(hint));
|
this._authPrompt.setHint(_("(e.g., user or %s)").format(hint));
|
||||||
},
|
},
|
||||||
|
|
||||||
_askForUsernameAndLogIn: function() {
|
_askForUsernameAndBeginVerification: function() {
|
||||||
this._authPrompt.setPasswordChar('');
|
this._authPrompt.setPasswordChar('');
|
||||||
this._authPrompt.setQuestion(_("Username: "));
|
this._authPrompt.setQuestion(_("Username: "));
|
||||||
|
|
||||||
@ -645,13 +651,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._authPrompt.updateSensitivity(false);
|
this._authPrompt.updateSensitivity(false);
|
||||||
let answer = this._authPrompt.getAnswer();
|
let answer = this._authPrompt.getAnswer();
|
||||||
this._authPrompt.clear();
|
this._authPrompt.clear();
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
this._authPrompt.startSpinning();
|
this._authPrompt.startSpinning();
|
||||||
this._authPrompt.begin({ userName: answer });
|
this._authPrompt.begin({ userName: answer });
|
||||||
|
|
||||||
realmManager.disconnect(realmSignalId)
|
realmManager.disconnect(realmSignalId)
|
||||||
realmManager.release();
|
realmManager.release();
|
||||||
}));
|
}));
|
||||||
this._authPrompt.cancelButton.hide();
|
|
||||||
this._showPrompt();
|
this._showPrompt();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -813,16 +819,26 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._userSelectionBox.visible = expanded;
|
this._userSelectionBox.visible = expanded;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideUserListAndLogIn: function() {
|
_hideUserList: function() {
|
||||||
this._setUserListExpanded(false);
|
this._setUserListExpanded(false);
|
||||||
if (this._userSelectionBox.visible)
|
if (this._userSelectionBox.visible)
|
||||||
GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
||||||
this._askForUsernameAndLogIn();
|
},
|
||||||
|
|
||||||
|
_hideUserListAskForUsernameAndBeginVerification: function() {
|
||||||
|
this._hideUserList();
|
||||||
|
this._askForUsernameAndBeginVerification();
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideUserListAndBeginVerification: function() {
|
||||||
|
this._hideUserList();
|
||||||
|
this._authPrompt.begin();
|
||||||
},
|
},
|
||||||
|
|
||||||
_showUserList: function() {
|
_showUserList: function() {
|
||||||
this._authPrompt.hide();
|
this._authPrompt.hide();
|
||||||
this._sessionMenuButton.close();
|
this._sessionMenuButton.close();
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
this._setUserListExpanded(true);
|
this._setUserListExpanded(true);
|
||||||
this._notListedButton.show();
|
this._notListedButton.show();
|
||||||
this._userList.actor.grab_key_focus();
|
this._userList.actor.grab_key_focus();
|
||||||
|
108
js/gdm/util.js
108
js/gdm/util.js
@ -13,15 +13,19 @@ const Fprint = imports.gdm.fingerprint;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
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 FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
|
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||||
const FADE_ANIMATION_TIME = 0.16;
|
const FADE_ANIMATION_TIME = 0.16;
|
||||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
|
const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication';
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
||||||
@ -116,8 +120,30 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._client = client;
|
this._client = client;
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||||
|
this._settings.connect('changed',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._updateDefaultService();
|
||||||
|
}));
|
||||||
|
this._updateDefaultService();
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||||
|
|
||||||
|
// We check for smartcards right away, since an inserted smartcard
|
||||||
|
// at startup should result in immediately initiating authentication.
|
||||||
|
// This is different than fingeprint readers, where we only check them
|
||||||
|
// after a user has been picked.
|
||||||
|
this._checkForSmartcard();
|
||||||
|
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._checkForSmartcard();
|
||||||
|
}));
|
||||||
|
this._smartcardManager.connect('smartcard-removed',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._checkForSmartcard();
|
||||||
|
}));
|
||||||
|
|
||||||
this._messageQueue = [];
|
this._messageQueue = [];
|
||||||
this._messageQueueTimeoutId = 0;
|
this._messageQueueTimeoutId = 0;
|
||||||
this.hasPendingMessages = false;
|
this.hasPendingMessages = false;
|
||||||
@ -148,8 +174,10 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
if (this._cancellable)
|
if (this._cancellable)
|
||||||
this._cancellable.cancel();
|
this._cancellable.cancel();
|
||||||
|
|
||||||
if (this._userVerifier)
|
if (this._userVerifier) {
|
||||||
this._userVerifier.call_cancel_sync(null);
|
this._userVerifier.call_cancel_sync(null);
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
@ -244,6 +272,28 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_checkForSmartcard: function() {
|
||||||
|
let smartcardDetected;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||||
|
smartcardDetected = false;
|
||||||
|
else if (this.reauthenticating)
|
||||||
|
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
|
||||||
|
else
|
||||||
|
smartcardDetected = this._smartcardManager.hasInsertedTokens();
|
||||||
|
|
||||||
|
if (smartcardDetected != this.smartcardDetected) {
|
||||||
|
this.smartcardDetected = smartcardDetected;
|
||||||
|
|
||||||
|
if (this.smartcardDetected)
|
||||||
|
this._preemptingService = SMARTCARD_SERVICE_NAME;
|
||||||
|
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
|
||||||
|
this._preemptingService = null;
|
||||||
|
|
||||||
|
this.emit('smartcard-status-changed');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_reportInitError: function(where, error) {
|
_reportInitError: function(where, error) {
|
||||||
logError(error, where);
|
logError(error, where);
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
@ -300,11 +350,35 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getForegroundService: function() {
|
||||||
|
if (this._preemptingService)
|
||||||
|
return this._preemptingService;
|
||||||
|
|
||||||
|
return this._defaultService;
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceIsForeground: function(serviceName) {
|
||||||
|
return serviceName == this._getForegroundService();
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceIsDefault: function(serviceName) {
|
||||||
|
return serviceName == this._defaultService;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateDefaultService: function() {
|
||||||
|
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
||||||
|
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||||
|
else if (this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
||||||
|
},
|
||||||
|
|
||||||
_beginVerification: function() {
|
_beginVerification: function() {
|
||||||
this._hold.acquire();
|
this._hold.acquire();
|
||||||
|
|
||||||
if (this._userName) {
|
if (this._userName) {
|
||||||
this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification_for_user(this._getForegroundService(),
|
||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
@ -320,7 +394,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (this._haveFingerprintReader) {
|
if (this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) {
|
||||||
this._hold.acquire();
|
this._hold.acquire();
|
||||||
|
|
||||||
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
||||||
@ -340,7 +414,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification(this._getForegroundService(),
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
try {
|
try {
|
||||||
@ -358,39 +432,36 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onInfo: function(client, serviceName, info) {
|
_onInfo: function(client, serviceName, info) {
|
||||||
// We don't display fingerprint messages, because they
|
if (this.serviceIsForeground(serviceName)) {
|
||||||
// have words like UPEK in them. Instead we use the messages
|
this._queueMessage(info, 'login-dialog-message-info');
|
||||||
// as a cue to display our own message.
|
} else if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
||||||
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
|
||||||
this._haveFingerprintReader) {
|
this._haveFingerprintReader) {
|
||||||
|
// We don't show fingeprint messages directly since it's
|
||||||
|
// not the main auth service. Instead we use the messages
|
||||||
|
// as a cue to display our own message.
|
||||||
|
|
||||||
// Translators: this message is shown below the password entry field
|
// Translators: this message is shown below the password entry field
|
||||||
// to indicate the user can swipe their finger instead
|
// to indicate the user can swipe their finger instead
|
||||||
this.emit('show-login-hint', _("(or swipe finger)"));
|
this.emit('show-login-hint', _("(or swipe finger)"));
|
||||||
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
|
||||||
this._queueMessage(info, 'login-dialog-message-info');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onProblem: function(client, serviceName, problem) {
|
_onProblem: function(client, serviceName, problem) {
|
||||||
// we don't want to show auth failed messages to
|
if (!this.serviceIsForeground(serviceName))
|
||||||
// users who haven't enrolled their fingerprint.
|
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._queueMessage(problem, 'login-dialog-message-warning');
|
this._queueMessage(problem, 'login-dialog-message-warning');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
_onInfoQuery: function(client, serviceName, question) {
|
||||||
// We only expect questions to come from the main auth service
|
if (!this.serviceIsForeground(serviceName))
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, question, '');
|
this.emit('ask-question', 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 (!this.serviceIsForeground(serviceName))
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
||||||
@ -399,6 +470,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
// Clear previous attempts to authenticate
|
// Clear previous attempts to authenticate
|
||||||
this._failCounter = 0;
|
this._failCounter = 0;
|
||||||
|
this._updateDefaultService();
|
||||||
|
|
||||||
this.emit('reset');
|
this.emit('reset');
|
||||||
},
|
},
|
||||||
@ -455,7 +527,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// if the password service fails, then cancel everything.
|
// if the password service fails, then cancel everything.
|
||||||
// But if, e.g., fingerprint fails, still give
|
// But if, e.g., fingerprint fails, still give
|
||||||
// password authentication a chance to succeed
|
// password authentication a chance to succeed
|
||||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
if (this.serviceIsForeground(serviceName)) {
|
||||||
this._verificationFailed(true);
|
this._verificationFailed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
275
js/misc/objectManager.js
Normal file
275
js/misc/objectManager.js
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
// Specified in the D-Bus specification here:
|
||||||
|
// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
|
||||||
|
const ObjectManagerIface = <interface name="org.freedesktop.DBus.ObjectManager">
|
||||||
|
<method name="GetManagedObjects">
|
||||||
|
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<signal name="InterfacesAdded">
|
||||||
|
<arg name="objectPath" type="o"/>
|
||||||
|
<arg name="interfaces" type="a{sa{sv}}" />
|
||||||
|
</signal>
|
||||||
|
<signal name="InterfacesRemoved">
|
||||||
|
<arg name="objectPath" type="o"/>
|
||||||
|
<arg name="interfaces" type="as" />
|
||||||
|
</signal>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
|
||||||
|
|
||||||
|
const ObjectManager = new Lang.Class({
|
||||||
|
Name: 'ObjectManager',
|
||||||
|
_init: function(params) {
|
||||||
|
params = Params.parse(params, { connection: null,
|
||||||
|
name: null,
|
||||||
|
objectPath: null,
|
||||||
|
knownInterfaces: null,
|
||||||
|
cancellable: null,
|
||||||
|
onLoaded: null });
|
||||||
|
|
||||||
|
this._connection = params.connection;
|
||||||
|
this._serviceName = params.name;
|
||||||
|
this._managerPath = params.objectPath;
|
||||||
|
this._cancellable = params.cancellable;
|
||||||
|
|
||||||
|
this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection,
|
||||||
|
g_interface_name: ObjectManagerInfo.name,
|
||||||
|
g_interface_info: ObjectManagerInfo,
|
||||||
|
g_name: this._serviceName,
|
||||||
|
g_object_path: this._managerPath,
|
||||||
|
g_flags: Gio.DBusProxyFlags.NONE });
|
||||||
|
|
||||||
|
this._interfaceInfos = {};
|
||||||
|
this._objects = {};
|
||||||
|
this._interfaces = {};
|
||||||
|
this._pendingProxies = [];
|
||||||
|
this._onLoaded = params.onLoaded;
|
||||||
|
|
||||||
|
if (params.knownInterfaces)
|
||||||
|
this._registerInterfaces(params.knownInterfaces);
|
||||||
|
|
||||||
|
this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, this._onManagerProxyLoaded));
|
||||||
|
},
|
||||||
|
|
||||||
|
_addInterface: function(objectPath, interfaceName, onFinished) {
|
||||||
|
let info = this._interfaceInfos[interfaceName];
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let proxy = new Gio.DBusProxy({ g_connection: this._connection,
|
||||||
|
g_name: this._serviceName,
|
||||||
|
g_object_path: objectPath,
|
||||||
|
g_interface_name: interfaceName,
|
||||||
|
g_interface_info: info,
|
||||||
|
g_flags: Gio.DBusProxyFlags.NONE });
|
||||||
|
|
||||||
|
this._pendingProxies.push(proxy);
|
||||||
|
|
||||||
|
proxy.init_async(GLib.PRIORITY_DEFAULT,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, function(initable, result) {
|
||||||
|
let index = this._pendingProxies.indexOf(proxy);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
this._pendingProxies.splice(index, 1);
|
||||||
|
|
||||||
|
let error = null;
|
||||||
|
try {
|
||||||
|
initable.init_finish(result);
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'could not initialize proxy for interface ' + interfaceName);
|
||||||
|
|
||||||
|
if (onFinished)
|
||||||
|
onFinished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isNewObject;
|
||||||
|
|
||||||
|
if (!this._objects[objectPath]) {
|
||||||
|
this._objects[objectPath] = {};
|
||||||
|
isNewObject = true;
|
||||||
|
} else {
|
||||||
|
isNewObject = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._objects[objectPath][interfaceName] = proxy;
|
||||||
|
|
||||||
|
if (!this._interfaces[interfaceName])
|
||||||
|
this._interfaces[interfaceName] = [];
|
||||||
|
|
||||||
|
this._interfaces[interfaceName].push(proxy);
|
||||||
|
|
||||||
|
if (isNewObject)
|
||||||
|
this.emit('object-added', objectPath);
|
||||||
|
|
||||||
|
this.emit('interface-added', interfaceName, proxy);
|
||||||
|
|
||||||
|
if (onFinished)
|
||||||
|
onFinished();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeInterface: function(objectPath, interfaceName) {
|
||||||
|
if (!this._objects[objectPath])
|
||||||
|
return;
|
||||||
|
|
||||||
|
let proxy = this._objects[objectPath][interfaceName];
|
||||||
|
|
||||||
|
if (this._interfaces[interfaceName]) {
|
||||||
|
let index = this._interfaces[interfaceName].indexOf(proxy);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
this._interfaces[interfaceName].splice(index, 1);
|
||||||
|
|
||||||
|
if (this._interfaces[interfaceName].length == 0)
|
||||||
|
delete this._interfaces[interfaceName];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('interface-removed', interfaceName, proxy);
|
||||||
|
|
||||||
|
this._objects[objectPath][interfaceName] = null;
|
||||||
|
|
||||||
|
if (Object.keys(this._objects[objectPath]).length == 0) {
|
||||||
|
delete this._objects[objectPath];
|
||||||
|
this.emit('object-removed', objectPath);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onManagerProxyLoaded: function(initable, result) {
|
||||||
|
let error = null;
|
||||||
|
try {
|
||||||
|
initable.init_finish(result);
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'could not initialize object manager for object ' + params.name);
|
||||||
|
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._managerProxy.connectSignal('InterfacesAdded',
|
||||||
|
Lang.bind(this, function(objectManager, sender, [objectPath, interfaces]) {
|
||||||
|
let interfaceNames = Object.keys(interfaces);
|
||||||
|
for (let i = 0; i < interfaceNames.length; i++)
|
||||||
|
this._addInterface(objectPath, interfaceNames[i]);
|
||||||
|
}));
|
||||||
|
this._managerProxy.connectSignal('InterfacesRemoved',
|
||||||
|
Lang.bind(this, function(objectManager, sender, [objectPath, interfaceNames]) {
|
||||||
|
for (let i = 0; i < interfaceNames.length; i++)
|
||||||
|
this._removeInterface(objectPath, interfaceNames[i]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
this._managerProxy.GetManagedObjectsRemote(Lang.bind(this, function(result, error) {
|
||||||
|
if (!result) {
|
||||||
|
if (error) {
|
||||||
|
logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [objects] = result;
|
||||||
|
|
||||||
|
if (Object.keys(this._interfaceInfos).length == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let numLoadInhibitors = 0;
|
||||||
|
|
||||||
|
// First inhibitor is to prevent onLoaded from getting
|
||||||
|
// called until all interfaces have started being added.
|
||||||
|
// Subsequent inhibitors are to prevent onLoaded from getting
|
||||||
|
// called until all interfaces finish getting added.
|
||||||
|
numLoadInhibitors++;
|
||||||
|
let objectPaths = Object.keys(objects);
|
||||||
|
for (let i = 0; i < objectPaths.length; i++) {
|
||||||
|
let objectPath = objectPaths[i];
|
||||||
|
let object = objects[objectPath];
|
||||||
|
|
||||||
|
let interfaceNames = Object.keys(object);
|
||||||
|
for (let j = 0; j < interfaceNames.length; j++) {
|
||||||
|
let interfaceName = interfaceNames[j];
|
||||||
|
|
||||||
|
numLoadInhibitors++;
|
||||||
|
this._addInterface(objectPath,
|
||||||
|
interfaceName,
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
numLoadInhibitors--;
|
||||||
|
|
||||||
|
if (numLoadInhibitors == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numLoadInhibitors--;
|
||||||
|
|
||||||
|
if (numLoadInhibitors == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_registerInterfaces: function(interfaces) {
|
||||||
|
for (let i = 0; i < interfaces.length; i++) {
|
||||||
|
let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]);
|
||||||
|
|
||||||
|
this._interfaceInfos[info.name] = info;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getProxy: function(objectPath, interfaceName) {
|
||||||
|
let object = this._objects[objectPath];
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return object[interfaceName];
|
||||||
|
},
|
||||||
|
|
||||||
|
getProxiesForInterface: function(interfaceName) {
|
||||||
|
let proxyList = this._interfaces[interfaceName];
|
||||||
|
|
||||||
|
if (!proxyList)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return proxyList;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllProxies: function() {
|
||||||
|
let proxies = [];
|
||||||
|
|
||||||
|
let objectPaths = Object.keys(this._objects);
|
||||||
|
for (let i = 0; i < objectPaths.length; i++) {
|
||||||
|
let object = this._objects[objectPaths];
|
||||||
|
|
||||||
|
let interfaceNames = Object.keys(object);
|
||||||
|
for (let j = 0; i < interfaceNames.length; i++) {
|
||||||
|
let interfaceName = interfaceNames[i];
|
||||||
|
if (object[interfaceName])
|
||||||
|
proxies.push(object(interfaceName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxies;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ObjectManager.prototype);
|
142
js/misc/smartcardManager.js
Normal file
142
js/misc/smartcardManager.js
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const ObjectManager = imports.misc.objectManager;
|
||||||
|
|
||||||
|
const _SMARTCARD_SERVICE_DBUS_NAME = "org.gnome.SettingsDaemon.Smartcard";
|
||||||
|
|
||||||
|
const SmartcardManagerIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Manager">
|
||||||
|
<method name="GetLoginToken">
|
||||||
|
<arg name="token" type="o" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetInsertedTokens">
|
||||||
|
<arg name="tokens" type="ao" direction="out"/>
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SmartcardTokenIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Token">
|
||||||
|
<property name="Name" type="s" access="read"/>
|
||||||
|
<property name="Driver" type="o" access="read"/>
|
||||||
|
<property name="IsInserted" type="b" access="read"/>
|
||||||
|
<property name="UsedToLogin" type="b" access="read"/>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SmartcardDriverIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Driver">
|
||||||
|
<property name="Library" type="s" access="read"/>
|
||||||
|
<property name="Description" type="s" access="read"/>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
let _smartcardManager = null;
|
||||||
|
|
||||||
|
function getSmartcardManager() {
|
||||||
|
if (_smartcardManager == null)
|
||||||
|
_smartcardManager = new SmartcardManager();
|
||||||
|
|
||||||
|
return _smartcardManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmartcardManager = new Lang.Class({
|
||||||
|
Name: 'SmartcardManager',
|
||||||
|
_init: function() {
|
||||||
|
this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session,
|
||||||
|
name: _SMARTCARD_SERVICE_DBUS_NAME,
|
||||||
|
objectPath: '/org/gnome/SettingsDaemon/Smartcard',
|
||||||
|
knownInterfaces: [ SmartcardManagerIface,
|
||||||
|
SmartcardTokenIface,
|
||||||
|
SmartcardDriverIface ],
|
||||||
|
onLoaded: Lang.bind(this, this._onLoaded) });
|
||||||
|
this._insertedTokens = {};
|
||||||
|
this._removedTokens = {};
|
||||||
|
this._loginToken = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onLoaded: function() {
|
||||||
|
let tokens = this._objectManager.getProxiesForInterface('org.gnome.SettingsDaemon.Smartcard.Token');
|
||||||
|
|
||||||
|
for (let i = 0; i < tokens.length; i++)
|
||||||
|
this._addToken(tokens[i]);
|
||||||
|
|
||||||
|
this._objectManager.connect('interface-added', Lang.bind(this, function(objectManager, interfaceName, proxy) {
|
||||||
|
if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token')
|
||||||
|
this._addToken(proxy);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._objectManager.connect('interface-removed', Lang.bind(this, function(objectManager, interfaceName, proxy) {
|
||||||
|
if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token')
|
||||||
|
this._removeToken(proxy);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateToken: function(token) {
|
||||||
|
let objectPath = token.get_object_path();
|
||||||
|
|
||||||
|
delete this._insertedTokens[objectPath];
|
||||||
|
delete this._removedTokens[objectPath];
|
||||||
|
|
||||||
|
if (token.IsInserted)
|
||||||
|
this._insertedTokens[objectPath] = token;
|
||||||
|
else
|
||||||
|
this._removedTokens[objectPath] = token;
|
||||||
|
|
||||||
|
if (token.UsedToLogin)
|
||||||
|
this._loginToken = token;
|
||||||
|
},
|
||||||
|
|
||||||
|
_addToken: function(token) {
|
||||||
|
this._updateToken(token);
|
||||||
|
|
||||||
|
token.connect('g-properties-changed',
|
||||||
|
Lang.bind(this, function(proxy, properties) {
|
||||||
|
if ('IsInserted' in properties.deep_unpack()) {
|
||||||
|
this._updateToken(token);
|
||||||
|
|
||||||
|
if (token.IsInserted) {
|
||||||
|
this.emit('smartcard-inserted', token.Name);
|
||||||
|
} else {
|
||||||
|
this.emit('smartcard-removed', token.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Emit a smartcard-inserted at startup if it's already plugged in
|
||||||
|
if (token.IsInserted)
|
||||||
|
this.emit('smartcard-inserted', token.Name);
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeToken: function(token) {
|
||||||
|
let objectPath = token.get_object_path();
|
||||||
|
|
||||||
|
if (objectPath) {
|
||||||
|
if (this._removedTokens[objectPath] == token) {
|
||||||
|
delete this._removedTokens[objectPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._insertedTokens[objectPath] == token) {
|
||||||
|
delete this._insertedTokens[objectPath];
|
||||||
|
this.emit('smartcard-removed', token.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token.disconnectAll();
|
||||||
|
},
|
||||||
|
|
||||||
|
hasInsertedTokens: function() {
|
||||||
|
return Object.keys(this._insertedTokens).length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasInsertedLoginToken: function() {
|
||||||
|
if (!this._loginToken)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!this._loginToken.IsInserted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(SmartcardManager.prototype);
|
@ -23,6 +23,7 @@ const Main = imports.ui.main;
|
|||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
@ -516,6 +517,13 @@ const ScreenShield = new Lang.Class({
|
|||||||
|
|
||||||
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
||||||
|
|
||||||
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
if (this._isLocked)
|
||||||
|
this._liftShield(true, 0);
|
||||||
|
}));
|
||||||
|
|
||||||
this._inhibitor = null;
|
this._inhibitor = null;
|
||||||
this._aboutToSuspend = false;
|
this._aboutToSuspend = false;
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
@ -49,8 +49,9 @@ const UnlockDialog = new Lang.Class({
|
|||||||
factor: 0.5 }));
|
factor: 0.5 }));
|
||||||
|
|
||||||
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
||||||
|
this._authPrompt.connect('failed', Lang.bind(this, this._fail));
|
||||||
|
this._authPrompt.connect('cancelled', Lang.bind(this, this._fail));
|
||||||
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._authPrompt.setUser(this._user);
|
|
||||||
this._authPrompt.setPasswordChar('\u25cf');
|
this._authPrompt.setPasswordChar('\u25cf');
|
||||||
this._authPrompt.nextButton.label = _("Unlock");
|
this._authPrompt.nextButton.label = _("Unlock");
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this._otherUserButton = null;
|
this._otherUserButton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._authPrompt.begin({ userName: this._userName });
|
this._authPrompt.reset();
|
||||||
this._updateSensitivity(true);
|
this._updateSensitivity(true);
|
||||||
|
|
||||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
||||||
@ -92,15 +93,25 @@ const UnlockDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_fail: function() {
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
},
|
},
|
||||||
|
|
||||||
_escape: function() {
|
_onReset: function(authPrompt, beginRequest) {
|
||||||
if (this.allowCancel) {
|
let userName;
|
||||||
this._authPrompt.cancel();
|
if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
|
||||||
this.emit('failed');
|
this._authPrompt.setUser(this._user);
|
||||||
|
userName = this._userName;
|
||||||
|
} else {
|
||||||
|
userName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._authPrompt.begin({ userName: userName });
|
||||||
|
},
|
||||||
|
|
||||||
|
_escape: function() {
|
||||||
|
if (this.allowCancel)
|
||||||
|
this._authPrompt.cancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_otherUserClicked: function(button, event) {
|
_otherUserClicked: function(button, event) {
|
||||||
|
Loading…
Reference in New Issue
Block a user