diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index 8a46559d9..d1f243fd7 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -21,6 +21,7 @@ const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000; const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300; const MESSAGE_FADE_OUT_ANIMATION_TIME = 500; +const PREEMPTIVE_ANSWER_TIMEOUT = 500; /** @enum {number} */ export const AuthPromptMode = { @@ -70,6 +71,8 @@ export const AuthPrompt = GObject.registerClass({ this._defaultButtonWellActor = null; this._cancelledRetries = 0; + this._idleMonitor = global.backend.get_core_idle_monitor(); + let reauthenticationOnly; if (this._mode === AuthPromptMode.UNLOCK_ONLY) reauthenticationOnly = true; @@ -127,8 +130,14 @@ export const AuthPrompt = GObject.registerClass({ } _onDestroy() { + if (this._preemptiveAnswerWatchId) { + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + } + this._inactiveEntry.destroy(); this._inactiveEntry = null; + this._userVerifier.destroy(); this._userVerifier = null; } @@ -211,7 +220,7 @@ export const AuthPrompt = GObject.registerClass({ [this._textEntry, this._passwordEntry].forEach(entry => { entry.clutter_text.connect('text-changed', () => { - if (!this._userVerifier.hasPendingMessages) + if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer) this._fadeOutMessage(); }); @@ -275,13 +284,19 @@ export const AuthPrompt = GObject.registerClass({ this.verificationStatus = AuthPromptStatus.VERIFICATION_IN_PROGRESS; this.updateSensitivity(false); - if (shouldSpin) - this.startSpinning(); + if (this._queryingService) { + if (shouldSpin) + this.startSpinning(); - if (this._queryingService) this._userVerifier.answerQuery(this._queryingService, this._entry.text); - else + } else { this._preemptiveAnswer = this._entry.text; + } + + if (this._preemptiveAnswerWatchId) { + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + } this.emit('next'); } @@ -492,6 +507,11 @@ export const AuthPrompt = GObject.registerClass({ } setQuestion(question) { + if (this._preemptiveAnswerWatchId) { + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + } + this._entry.hint_text = question; this._authList.hide(); @@ -613,6 +633,19 @@ export const AuthPrompt = GObject.registerClass({ this._updateEntry(false); } + _onUserStoppedTypePreemptiveAnswer() { + if (!this._preemptiveAnswerWatchId || + this._preemptiveAnswer || + this._queryingService) + return; + + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = 0; + + this._entry.text = ''; + this.updateSensitivity(false); + } + reset() { let oldStatus = this.verificationStatus; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; @@ -620,6 +653,11 @@ export const AuthPrompt = GObject.registerClass({ this.cancelButton.can_focus = this._hasCancelButton; this._preemptiveAnswer = null; + if (this._preemptiveAnswerWatchId) + this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId); + this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch(PREEMPTIVE_ANSWER_TIMEOUT, + this._onUserStoppedTypePreemptiveAnswer.bind(this)); + if (this._userVerifier) this._userVerifier.cancel(); diff --git a/js/gdm/util.js b/js/gdm/util.js index 07cc17a33..bfda4c838 100644 --- a/js/gdm/util.js +++ b/js/gdm/util.js @@ -642,7 +642,10 @@ export class ShellUserVerifier extends Signals.EventEmitter { } _getDetectedDefaultService() { - if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) + if (this._smartcardManager.loggedInWithToken() && + this._smartcardManager.lockOnRemoval()) + return SMARTCARD_SERVICE_NAME; + else if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY)) return PASSWORD_SERVICE_NAME; else if (this._smartcardManager) return SMARTCARD_SERVICE_NAME; diff --git a/js/misc/smartcardManager.js b/js/misc/smartcardManager.js index 32573cd38..daba703be 100644 --- a/js/misc/smartcardManager.js +++ b/js/misc/smartcardManager.js @@ -5,6 +5,9 @@ import * as Signals from './signals.js'; import * as ObjectManager from './objectManager.js'; +const SMARTCARD_SETTINGS_SCHEMA = 'org.gnome.settings-daemon.peripherals.smartcard'; +const SMARTCARD_REMOVAL_ACTION = 'removal-action'; + const SmartcardTokenIface = ` @@ -38,6 +41,7 @@ class SmartcardManager extends Signals.EventEmitter { knownInterfaces: [SmartcardTokenIface], onLoaded: this._onLoaded.bind(this), }); + this._settings = new Gio.Settings({schema_id: SMARTCARD_SETTINGS_SCHEMA}); this._insertedTokens = {}; this._loginToken = null; } @@ -74,7 +78,7 @@ class SmartcardManager extends Signals.EventEmitter { _addToken(token) { this._updateToken(token); - token.connect('g-properties-changed', (proxy, properties) => { + token._smartcardSignalId = token.connect('g-properties-changed', (proxy, properties) => { const isInsertedChanged = !!properties.lookup_value('IsInserted', null); if (isInsertedChanged) { this._updateToken(token); @@ -99,10 +103,13 @@ class SmartcardManager extends Signals.EventEmitter { this.emit('smartcard-removed', token); } + if (token._smartcardSignalId) { + token.disconnect(token._smartcardSignalId); + delete token._smartcardSignalId; + } + if (this._loginToken === token) this._loginToken = null; - - token.disconnectAll(); } hasInsertedTokens() { @@ -117,5 +124,16 @@ class SmartcardManager extends Signals.EventEmitter { return false; return true; + }, + + loggedInWithToken() { + if (this._loginToken) + return true; + + return false; + } + + lockOnRemoval() { + return this._settings.get_string(SMARTCARD_REMOVAL_ACTION) === 'lock-screen'; } } diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js index d2236fb90..b62440dff 100644 --- a/js/ui/screenShield.js +++ b/js/ui/screenShield.js @@ -94,8 +94,10 @@ export class ScreenShield extends Signals.EventEmitter { this._smartcardManager = SmartcardManager.getSmartcardManager(); this._smartcardManager.connect('smartcard-inserted', (manager, token) => { - if (this._isLocked && token.UsedToLogin) + if (this._isLocked && token.UsedToLogin) { + this._wakeUpScreen(); this._activateDialog(); + } }); this._credentialManagers = {};