Compare commits
	
		
			16 Commits
		
	
	
		
			issue154
			...
			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/loginManager.js	\
 | 
			
		||||
	misc/modemManager.js	\
 | 
			
		||||
	misc/objectManager.js	\
 | 
			
		||||
	misc/params.js		\
 | 
			
		||||
	misc/smartcardManager.js \
 | 
			
		||||
	misc/util.js		\
 | 
			
		||||
	perf/core.js		\
 | 
			
		||||
	ui/altTab.js		\
 | 
			
		||||
 
 | 
			
		||||
@@ -24,11 +24,23 @@ const AuthPromptMode = {
 | 
			
		||||
    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({
 | 
			
		||||
    Name: 'AuthPrompt',
 | 
			
		||||
 | 
			
		||||
    _init: function(gdmClient, mode) {
 | 
			
		||||
        this.verifyingUser = false;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
 | 
			
		||||
 | 
			
		||||
        this._gdmClient = gdmClient;
 | 
			
		||||
        this._mode = mode;
 | 
			
		||||
@@ -48,6 +60,8 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
 | 
			
		||||
        this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
 | 
			
		||||
        this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
 | 
			
		||||
        this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
 | 
			
		||||
        this.smartcardDetected = this._userVerifier.smartcardDetected;
 | 
			
		||||
 | 
			
		||||
        this.connect('next', Lang.bind(this, function() {
 | 
			
		||||
                         this.updateSensitivity(false);
 | 
			
		||||
@@ -123,6 +137,8 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        this._userVerifier.clear();
 | 
			
		||||
        this._userVerifier.disconnectAll();
 | 
			
		||||
        this._userVerifier = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _initButtons: function() {
 | 
			
		||||
@@ -193,11 +209,6 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        this.setPasswordChar(passwordChar);
 | 
			
		||||
        this.setQuestion(question);
 | 
			
		||||
 | 
			
		||||
        if (this.verifyingUser)
 | 
			
		||||
            this.cancelButton.show();
 | 
			
		||||
        else
 | 
			
		||||
            this.cancelButton.hide();
 | 
			
		||||
 | 
			
		||||
        if (passwordChar) {
 | 
			
		||||
            if (this._userVerifier.reauthenticating)
 | 
			
		||||
                this.nextButton.label = _("Unlock");
 | 
			
		||||
@@ -211,8 +222,23 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        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) {
 | 
			
		||||
        this.setMessage(message, styleClass);
 | 
			
		||||
        this.emit('prompted');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVerificationFailed: function() {
 | 
			
		||||
@@ -220,16 +246,18 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        this.updateSensitivity(true);
 | 
			
		||||
        this.setActorInDefaultButtonWell(null);
 | 
			
		||||
        this.userVerified = false;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onVerificationComplete: function() {
 | 
			
		||||
        this.userVerified = true;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onReset: function() {
 | 
			
		||||
        if (!this.userVerified)
 | 
			
		||||
        if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) {
 | 
			
		||||
            this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
 | 
			
		||||
            this.reset();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onShowLoginHint: function(verifier, message) {
 | 
			
		||||
@@ -401,8 +429,12 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    reset: function() {
 | 
			
		||||
        this.verifyingUser = false;
 | 
			
		||||
        this.userVerified = false;
 | 
			
		||||
        let oldStatus = this.verificationStatus;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
 | 
			
		||||
 | 
			
		||||
        if (oldStatus == AuthPromptStatus.VERIFYING)
 | 
			
		||||
            this._userVerifier.cancel();
 | 
			
		||||
 | 
			
		||||
        this._queryingService = null;
 | 
			
		||||
        this.clear();
 | 
			
		||||
        this._message.opacity = 0;
 | 
			
		||||
@@ -410,7 +442,25 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
        this.stopSpinning();
 | 
			
		||||
        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) {
 | 
			
		||||
@@ -432,7 +482,7 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
            hold = new Batch.Hold();
 | 
			
		||||
 | 
			
		||||
        this._userVerifier.begin(params.userName, hold);
 | 
			
		||||
        this.verifyingUser = true;
 | 
			
		||||
        this.verificationStatus = AuthPromptStatus.VERIFYING;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    finish: function(onComplete) {
 | 
			
		||||
@@ -449,10 +499,8 @@ const AuthPrompt = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    cancel: function() {
 | 
			
		||||
        if (this.verifyingUser)
 | 
			
		||||
            this._userVerifier.cancel();
 | 
			
		||||
 | 
			
		||||
        this.reset();
 | 
			
		||||
        this.emit('cancelled');
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
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.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.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
 | 
			
		||||
@@ -475,7 +475,12 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
                                                x_align: St.Align.START,
 | 
			
		||||
                                                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._userSelectionBox.add(this._notListedButton,
 | 
			
		||||
@@ -529,8 +534,8 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
        if (disableUserList != this._disableUserList) {
 | 
			
		||||
            this._disableUserList = disableUserList;
 | 
			
		||||
 | 
			
		||||
            if (!this._authPrompt.verifyingUser)
 | 
			
		||||
                this._reset();
 | 
			
		||||
            if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
 | 
			
		||||
                this._authPrompt.reset();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -569,24 +574,25 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        if (this._shouldShowSessionMenuButton())
 | 
			
		||||
            this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
 | 
			
		||||
 | 
			
		||||
        this._authPrompt.cancelButton.show();
 | 
			
		||||
 | 
			
		||||
        this._showPrompt();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _reset: function() {
 | 
			
		||||
        if (this._authPrompt.verifyingUser)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
    _onReset: function(authPrompt, beginRequest) {
 | 
			
		||||
        this._sessionMenuButton.updateSensitivity(true);
 | 
			
		||||
 | 
			
		||||
        this._user = null;
 | 
			
		||||
 | 
			
		||||
        if (this._disableUserList)
 | 
			
		||||
            this._hideUserListAndLogIn();
 | 
			
		||||
        else
 | 
			
		||||
            this._showUserList();
 | 
			
		||||
        if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
 | 
			
		||||
            if (this._disableUserList) {
 | 
			
		||||
                this._authPrompt.cancelButton.hide();
 | 
			
		||||
                this._hideUserListAskForUsernameAndBeginVerification();
 | 
			
		||||
            } else {
 | 
			
		||||
                this._showUserList();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._authPrompt.cancelButton.hide();
 | 
			
		||||
            this._hideUserListAndBeginVerification();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDefaultSessionChanged: function(client, sessionId) {
 | 
			
		||||
@@ -630,7 +636,7 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
        this._authPrompt.setHint(_("(e.g., user or %s)").format(hint));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _askForUsernameAndLogIn: function() {
 | 
			
		||||
    _askForUsernameAndBeginVerification: function() {
 | 
			
		||||
        this._authPrompt.setPasswordChar('');
 | 
			
		||||
        this._authPrompt.setQuestion(_("Username: "));
 | 
			
		||||
 | 
			
		||||
@@ -645,13 +651,13 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
                                                        this._authPrompt.updateSensitivity(false);
 | 
			
		||||
                                                        let answer = this._authPrompt.getAnswer();
 | 
			
		||||
                                                        this._authPrompt.clear();
 | 
			
		||||
                                                        this._authPrompt.cancelButton.show();
 | 
			
		||||
                                                        this._authPrompt.startSpinning();
 | 
			
		||||
                                                        this._authPrompt.begin({ userName: answer });
 | 
			
		||||
 | 
			
		||||
                                                        realmManager.disconnect(realmSignalId)
 | 
			
		||||
                                                        realmManager.release();
 | 
			
		||||
                                                    }));
 | 
			
		||||
        this._authPrompt.cancelButton.hide();
 | 
			
		||||
        this._showPrompt();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -813,16 +819,26 @@ const LoginDialog = new Lang.Class({
 | 
			
		||||
        this._userSelectionBox.visible = expanded;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideUserListAndLogIn: function() {
 | 
			
		||||
    _hideUserList: function() {
 | 
			
		||||
        this._setUserListExpanded(false);
 | 
			
		||||
        if (this._userSelectionBox.visible)
 | 
			
		||||
            GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
 | 
			
		||||
        this._askForUsernameAndLogIn();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideUserListAskForUsernameAndBeginVerification: function() {
 | 
			
		||||
        this._hideUserList();
 | 
			
		||||
        this._askForUsernameAndBeginVerification();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideUserListAndBeginVerification: function() {
 | 
			
		||||
        this._hideUserList();
 | 
			
		||||
        this._authPrompt.begin();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _showUserList: function() {
 | 
			
		||||
        this._authPrompt.hide();
 | 
			
		||||
        this._sessionMenuButton.close();
 | 
			
		||||
        this._authPrompt.cancelButton.show();
 | 
			
		||||
        this._setUserListExpanded(true);
 | 
			
		||||
        this._notListedButton.show();
 | 
			
		||||
        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 Params = imports.misc.params;
 | 
			
		||||
const ShellEntry = imports.ui.shellEntry;
 | 
			
		||||
const SmartcardManager = imports.misc.smartcardManager;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
 | 
			
		||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
 | 
			
		||||
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
 | 
			
		||||
const FADE_ANIMATION_TIME = 0.16;
 | 
			
		||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
 | 
			
		||||
 | 
			
		||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
 | 
			
		||||
const PASSWORD_AUTHENTICATION_KEY = 'enable-password-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_TEXT_KEY = 'banner-message-text';
 | 
			
		||||
const ALLOWED_FAILURES_KEY = 'allowed-failures';
 | 
			
		||||
@@ -116,8 +120,30 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        this._client = client;
 | 
			
		||||
 | 
			
		||||
        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._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._messageQueueTimeoutId = 0;
 | 
			
		||||
        this.hasPendingMessages = false;
 | 
			
		||||
@@ -148,8 +174,10 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        if (this._cancellable)
 | 
			
		||||
            this._cancellable.cancel();
 | 
			
		||||
 | 
			
		||||
        if (this._userVerifier)
 | 
			
		||||
        if (this._userVerifier) {
 | 
			
		||||
            this._userVerifier.call_cancel_sync(null);
 | 
			
		||||
            this.clear();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    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) {
 | 
			
		||||
        logError(error, where);
 | 
			
		||||
        this._hold.release();
 | 
			
		||||
@@ -300,11 +350,35 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        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() {
 | 
			
		||||
        this._hold.acquire();
 | 
			
		||||
 | 
			
		||||
        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._cancellable,
 | 
			
		||||
                                                                Lang.bind(this, function(obj, result) {
 | 
			
		||||
@@ -320,7 +394,7 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
                this._hold.release();
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
            if (this._haveFingerprintReader) {
 | 
			
		||||
            if (this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) {
 | 
			
		||||
                this._hold.acquire();
 | 
			
		||||
 | 
			
		||||
                this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
 | 
			
		||||
@@ -340,7 +414,7 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
 | 
			
		||||
            this._userVerifier.call_begin_verification(this._getForegroundService(),
 | 
			
		||||
                                                       this._cancellable,
 | 
			
		||||
                                                       Lang.bind(this, function(obj, result) {
 | 
			
		||||
                try {
 | 
			
		||||
@@ -358,39 +432,36 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _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 &&
 | 
			
		||||
        if (this.serviceIsForeground(serviceName)) {
 | 
			
		||||
            this._queueMessage(info, 'login-dialog-message-info');
 | 
			
		||||
        } else if (serviceName == FINGERPRINT_SERVICE_NAME &&
 | 
			
		||||
            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
 | 
			
		||||
            // to indicate the user can swipe their finger instead
 | 
			
		||||
            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) {
 | 
			
		||||
        // we don't want to show auth failed messages to
 | 
			
		||||
        // users who haven't enrolled their fingerprint.
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
        if (!this.serviceIsForeground(serviceName))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._queueMessage(problem, 'login-dialog-message-warning');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onInfoQuery: function(client, serviceName, question) {
 | 
			
		||||
        // We only expect questions to come from the main auth service
 | 
			
		||||
        if (serviceName != PASSWORD_SERVICE_NAME)
 | 
			
		||||
        if (!this.serviceIsForeground(serviceName))
 | 
			
		||||
            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)
 | 
			
		||||
        if (!this.serviceIsForeground(serviceName))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
 | 
			
		||||
@@ -399,6 +470,7 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
    _onReset: function() {
 | 
			
		||||
        // Clear previous attempts to authenticate
 | 
			
		||||
        this._failCounter = 0;
 | 
			
		||||
        this._updateDefaultService();
 | 
			
		||||
 | 
			
		||||
        this.emit('reset');
 | 
			
		||||
    },
 | 
			
		||||
@@ -455,7 +527,7 @@ const ShellUserVerifier = new Lang.Class({
 | 
			
		||||
        // 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) {
 | 
			
		||||
        if (this.serviceIsForeground(serviceName)) {
 | 
			
		||||
            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 MessageTray = imports.ui.messageTray;
 | 
			
		||||
const ShellDBus = imports.ui.shellDBus;
 | 
			
		||||
const SmartcardManager = imports.misc.smartcardManager;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const Util = imports.misc.util;
 | 
			
		||||
 | 
			
		||||
@@ -516,6 +517,13 @@ const ScreenShield = new Lang.Class({
 | 
			
		||||
 | 
			
		||||
        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._aboutToSuspend = false;
 | 
			
		||||
        this._loginManager = LoginManager.getLoginManager();
 | 
			
		||||
 
 | 
			
		||||
@@ -49,8 +49,9 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
                                                                     factor: 0.5 }));
 | 
			
		||||
 | 
			
		||||
        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.setUser(this._user);
 | 
			
		||||
        this._authPrompt.setPasswordChar('\u25cf');
 | 
			
		||||
        this._authPrompt.nextButton.label = _("Unlock");
 | 
			
		||||
 | 
			
		||||
@@ -74,7 +75,7 @@ const UnlockDialog = new Lang.Class({
 | 
			
		||||
            this._otherUserButton = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._authPrompt.begin({ userName: this._userName });
 | 
			
		||||
        this._authPrompt.reset();
 | 
			
		||||
        this._updateSensitivity(true);
 | 
			
		||||
 | 
			
		||||
        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');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _escape: function() {
 | 
			
		||||
        if (this.allowCancel) {
 | 
			
		||||
            this._authPrompt.cancel();
 | 
			
		||||
            this.emit('failed');
 | 
			
		||||
    _onReset: function(authPrompt, beginRequest) {
 | 
			
		||||
        let userName;
 | 
			
		||||
        if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
 | 
			
		||||
            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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user