diff --git a/x11/gnome/shell/Makefile b/x11/gnome/shell/Makefile index 8391c14a107..6b4241ab18e 100644 --- a/x11/gnome/shell/Makefile +++ b/x11/gnome/shell/Makefile @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile,v 1.208 2021/05/14 16:19:30 jasper Exp $ +# $OpenBSD: Makefile,v 1.209 2021/06/14 18:54:25 jasper Exp $ USE_WXNEEDED= Yes COMMENT= next generation GNOME shell GNOME_PROJECT= gnome-shell -GNOME_VERSION= 40.1 +GNOME_VERSION= 40.2 # GPLv2+ PERMIT_PACKAGE= Yes diff --git a/x11/gnome/shell/distinfo b/x11/gnome/shell/distinfo index e3c09ab54ee..d35306aa650 100644 --- a/x11/gnome/shell/distinfo +++ b/x11/gnome/shell/distinfo @@ -1,2 +1,2 @@ -SHA256 (gnome/gnome-shell-40.1.tar.xz) = 9j4r7Zm9iVjPMT2F9EoBjVn4UqBbqfKap8t0S+xvprc= -SIZE (gnome/gnome-shell-40.1.tar.xz) = 1876776 +SHA256 (gnome/gnome-shell-40.2.tar.xz) = Tp2CmwOfoK3TO7ZYP8e04Cjtjc/3r4pXfgnMZpiMKBw= +SIZE (gnome/gnome-shell-40.2.tar.xz) = 1869600 diff --git a/x11/gnome/shell/patches/patch-js_gdm_loginDialog_js b/x11/gnome/shell/patches/patch-js_gdm_loginDialog_js new file mode 100644 index 00000000000..620a85197b1 --- /dev/null +++ b/x11/gnome/shell/patches/patch-js_gdm_loginDialog_js @@ -0,0 +1,156 @@ +$OpenBSD: patch-js_gdm_loginDialog_js,v 1.3 2021/06/14 18:54:25 jasper Exp $ + +Index: js/gdm/loginDialog.js +--- js/gdm/loginDialog.js.orig ++++ js/gdm/loginDialog.js +@@ -42,6 +42,7 @@ var UserListItem = GObject.registerClass({ + _init(user) { + let layout = new St.BoxLayout({ + vertical: true, ++ x_align: Clutter.ActorAlign.START, + }); + super._init({ + style_class: 'login-dialog-user-list-item', +@@ -762,9 +763,6 @@ var LoginDialog = GObject.registerClass({ + + if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) + this._authPrompt.reset(); +- +- if (this._disableUserList && this._timedLoginUserListHold) +- this._timedLoginUserListHold.release(); + } + } + +@@ -858,7 +856,6 @@ var LoginDialog = GObject.registerClass({ + this._resetGreeterProxy(); + this._sessionMenuButton.updateSensitivity(true); + +- const previousUser = this._user; + this._user = null; + + if (this._nextSignalId) { +@@ -866,11 +863,7 @@ var LoginDialog = GObject.registerClass({ + this._nextSignalId = 0; + } + +- if (previousUser && beginRequest === AuthPrompt.BeginRequestType.REUSE_USERNAME) { +- this._user = previousUser; +- this._authPrompt.setUser(this._user); +- this._authPrompt.begin({ userName: previousUser.get_user_name() }); +- } else if (beginRequest === AuthPrompt.BeginRequestType.PROVIDE_USERNAME) { ++ if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) { + if (!this._disableUserList) + this._showUserList(); + else +@@ -1051,72 +1044,54 @@ var LoginDialog = GObject.registerClass({ + let loginItem = null; + let animationTime; + +- let tasks = [ +- () => { +- if (this._disableUserList) +- return; ++ let tasks = [() => this._waitForItemForUser(userName), + +- this._timedLoginUserListHold = this._waitForItemForUser(userName); +- }, ++ () => { ++ loginItem = this._userList.getItemFromUserName(userName); + +- () => { +- this._timedLoginUserListHold = null; ++ // If there is an animation running on the item, reset it. ++ loginItem.hideTimedLoginIndicator(); ++ }, + +- if (this._disableUserList) +- loginItem = this._authPrompt; +- else +- loginItem = this._userList.getItemFromUserName(userName); ++ () => { ++ // If we're just starting out, start on the right item. ++ if (!this._userManager.is_loaded) ++ this._userList.jumpToItem(loginItem); ++ }, + +- // If there is an animation running on the item, reset it. +- loginItem.hideTimedLoginIndicator(); +- }, ++ () => { ++ // This blocks the timed login animation until a few ++ // seconds after the user stops interacting with the ++ // login screen. + +- () => { +- if (this._disableUserList) +- return; ++ // We skip this step if the timed login delay is very short. ++ if (delay > _TIMED_LOGIN_IDLE_THRESHOLD) { ++ animationTime = delay - _TIMED_LOGIN_IDLE_THRESHOLD; ++ return this._blockTimedLoginUntilIdle(); ++ } else { ++ animationTime = delay; ++ return null; ++ } ++ }, + +- // If we're just starting out, start on the right item. +- if (!this._userManager.is_loaded) +- this._userList.jumpToItem(loginItem); +- }, ++ () => { ++ // If idle timeout is done, make sure the timed login indicator is shown ++ if (delay > _TIMED_LOGIN_IDLE_THRESHOLD && ++ this._authPrompt.visible) ++ this._authPrompt.cancel(); + +- () => { +- // This blocks the timed login animation until a few +- // seconds after the user stops interacting with the +- // login screen. ++ if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) { ++ this._userList.scrollToItem(loginItem); ++ loginItem.grab_key_focus(); ++ } ++ }, + +- // We skip this step if the timed login delay is very short. +- if (delay > _TIMED_LOGIN_IDLE_THRESHOLD) { +- animationTime = delay - _TIMED_LOGIN_IDLE_THRESHOLD; +- return this._blockTimedLoginUntilIdle(); +- } else { +- animationTime = delay; +- return null; +- } +- }, ++ () => loginItem.showTimedLoginIndicator(animationTime), + +- () => { +- if (this._disableUserList) +- return; +- +- // If idle timeout is done, make sure the timed login indicator is shown +- if (delay > _TIMED_LOGIN_IDLE_THRESHOLD && +- this._authPrompt.visible) +- this._authPrompt.cancel(); +- +- if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) { +- this._userList.scrollToItem(loginItem); +- loginItem.grab_key_focus(); +- } +- }, +- +- () => loginItem.showTimedLoginIndicator(animationTime), +- +- () => { +- this._timedLoginBatch = null; +- this._greeter.call_begin_auto_login_sync(userName, null); +- }, +- ]; ++ () => { ++ this._timedLoginBatch = null; ++ this._greeter.call_begin_auto_login_sync(userName, null); ++ }]; + + this._timedLoginBatch = new Batch.ConsecutiveBatch(this, tasks); + diff --git a/x11/gnome/shell/patches/patch-js_gdm_util_js b/x11/gnome/shell/patches/patch-js_gdm_util_js new file mode 100644 index 00000000000..81506b32ea5 --- /dev/null +++ b/x11/gnome/shell/patches/patch-js_gdm_util_js @@ -0,0 +1,558 @@ +$OpenBSD: patch-js_gdm_util_js,v 1.1 2021/06/14 18:54:25 jasper Exp $ + +Index: js/gdm/util.js +--- js/gdm/util.js.orig ++++ js/gdm/util.js +@@ -6,18 +6,13 @@ const { Clutter, Gdm, Gio, GLib } = imports.gi; + const Signals = imports.signals; + + const Batch = imports.gdm.batch; ++const Fprint = imports.gdm.fingerprint; + const OVirt = imports.gdm.oVirt; + const Vmware = imports.gdm.vmware; + const Main = imports.ui.main; +-const { loadInterfaceXML } = imports.misc.fileUtils; + const Params = imports.misc.params; + const SmartcardManager = imports.misc.smartcardManager; + +-const FprintManagerIface = loadInterfaceXML('net.reactivated.Fprint.Manager'); +-const FprintManagerProxy = Gio.DBusProxy.makeProxyWrapper(FprintManagerIface); +-const FprintDeviceIface = loadInterfaceXML('net.reactivated.Fprint.Device'); +-const FprintDeviceProxy = Gio.DBusProxy.makeProxyWrapper(FprintDeviceIface); +- + Gio._promisify(Gdm.Client.prototype, + 'open_reauthentication_channel', 'open_reauthentication_channel_finish'); + Gio._promisify(Gdm.Client.prototype, +@@ -46,22 +41,14 @@ var DISABLE_USER_LIST_KEY = 'disable-user-list'; + + // Give user 48ms to read each character of a PAM message + var USER_READ_TIME = 48; +-const FINGERPRINT_ERROR_TIMEOUT_WAIT = 15; + + var MessageType = { +- // Keep messages in order by priority + NONE: 0, +- HINT: 1, ++ ERROR: 1, + INFO: 2, +- ERROR: 3, ++ HINT: 3, + }; + +-const FingerprintReaderType = { +- NONE: 0, +- PRESS: 1, +- SWIPE: 2, +-}; +- + function fadeInActor(actor) { + if (actor.opacity == 255 && actor.visible) + return null; +@@ -151,12 +138,7 @@ var ShellUserVerifier = class { + this._updateDefaultService.bind(this)); + this._updateDefaultService(); + +- this._fprintManager = new FprintManagerProxy(Gio.DBus.system, +- 'net.reactivated.Fprint', +- '/net/reactivated/Fprint/Manager', +- null, +- null, +- Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES); ++ this._fprintManager = Fprint.FprintManager(); + this._smartcardManager = SmartcardManager.getSmartcardManager(); + + // We check for smartcards right away, since an inserted smartcard +@@ -173,10 +155,10 @@ var ShellUserVerifier = class { + + this._messageQueue = []; + this._messageQueueTimeoutId = 0; ++ this.hasPendingMessages = false; + this.reauthenticating = false; + + this._failCounter = 0; +- this._unavailableServices = new Set(); + + this._credentialManagers = {}; + this._credentialManagers[OVirt.SERVICE_NAME] = OVirt.getOVirtCredentialsManager(); +@@ -194,18 +176,6 @@ var ShellUserVerifier = class { + } + } + +- get hasPendingMessages() { +- return !!this._messageQueue.length; +- } +- +- get allowedFailures() { +- return this._settings.get_int(ALLOWED_FAILURES_KEY); +- } +- +- get currentMessage() { +- return this._messageQueue ? this._messageQueue[0] : null; +- } +- + begin(userName, hold) { + this._cancellable = new Gio.Cancellable(); + this._hold = hold; +@@ -234,7 +204,6 @@ var ShellUserVerifier = class { + + _clearUserVerifier() { + if (this._userVerifier) { +- this._disconnectSignals(); + this._userVerifier.run_dispose(); + this._userVerifier = null; + } +@@ -251,7 +220,7 @@ var ShellUserVerifier = class { + } + + destroy() { +- this.cancel(); ++ this.clear(); + + this._settings.run_dispose(); + this._settings = null; +@@ -271,19 +240,14 @@ var ShellUserVerifier = class { + if (!this.hasPendingMessages) { + this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); + } else { +- const cancellable = this._cancellable; + let signalId = this.connect('no-more-messages', () => { + this.disconnect(signalId); +- if (!cancellable.is_cancelled()) +- this._userVerifier.call_answer_query(serviceName, answer, cancellable, null); ++ this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null); + }); + } + } + + _getIntervalForMessage(message) { +- if (!message) +- return 0; +- + // We probably could be smarter here + return message.length * USER_READ_TIME; + } +@@ -294,72 +258,41 @@ var ShellUserVerifier = class { + + this._messageQueue = []; + ++ this.hasPendingMessages = false; + this.emit('no-more-messages'); + } + +- increaseCurrentMessageTimeout(interval) { +- if (!this._messageQueueTimeoutId && interval > 0) +- this._currentMessageExtraInterval = interval; +- } +- +- _serviceHasPendingMessages(serviceName) { +- return this._messageQueue.some(m => m.serviceName === serviceName); +- } +- +- _filterServiceMessages(serviceName, messageType) { +- // This function allows to remove queued messages for the @serviceName +- // whose type has lower priority than @messageType, replacing them +- // with a null message that will lead to clearing the prompt once done. +- if (this._serviceHasPendingMessages(serviceName)) +- this._queuePriorityMessage(serviceName, null, messageType); +- } +- + _queueMessageTimeout() { ++ if (this._messageQueue.length == 0) { ++ this.finishMessageQueue(); ++ return; ++ } ++ + if (this._messageQueueTimeoutId != 0) + return; + +- const message = this.currentMessage; ++ let message = this._messageQueue.shift(); + +- delete this._currentMessageExtraInterval; +- this.emit('show-message', message.serviceName, message.text, message.type); ++ this.emit('show-message', message.text, message.type); + + this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, +- message.interval + (this._currentMessageExtraInterval | 0), () => { +- this._messageQueueTimeoutId = 0; +- +- if (this._messageQueue.length > 1) { +- this._messageQueue.shift(); +- this._queueMessageTimeout(); +- } else { +- this.finishMessageQueue(); +- } +- +- return GLib.SOURCE_REMOVE; +- }); ++ message.interval, ++ () => { ++ this._messageQueueTimeoutId = 0; ++ this._queueMessageTimeout(); ++ return GLib.SOURCE_REMOVE; ++ }); + GLib.Source.set_name_by_id(this._messageQueueTimeoutId, '[gnome-shell] this._queueMessageTimeout'); + } + +- _queueMessage(serviceName, message, messageType) { ++ _queueMessage(message, messageType) { + let interval = this._getIntervalForMessage(message); + +- this._messageQueue.push({ serviceName, text: message, type: messageType, interval }); ++ this.hasPendingMessages = true; ++ this._messageQueue.push({ text: message, type: messageType, interval }); + this._queueMessageTimeout(); + } + +- _queuePriorityMessage(serviceName, message, messageType) { +- const newQueue = this._messageQueue.filter(m => { +- if (m.serviceName !== serviceName || m.type >= messageType) +- return m.text !== message; +- return false; +- }); +- +- if (!newQueue.includes(this.currentMessage)) +- this._clearMessageQueue(); +- +- this._messageQueue = newQueue; +- this._queueMessage(serviceName, message, messageType); +- } +- + _clearMessageQueue() { + this.finishMessageQueue(); + +@@ -367,11 +300,11 @@ var ShellUserVerifier = class { + GLib.source_remove(this._messageQueueTimeoutId); + this._messageQueueTimeoutId = 0; + } +- this.emit('show-message', null, null, MessageType.NONE); ++ this.emit('show-message', null, MessageType.NONE); + } + + _checkForFingerprintReader() { +- this._fingerprintReaderType = FingerprintReaderType.NONE; ++ this._haveFingerprintReader = false; + + if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY) || + this._fprintManager == null) { +@@ -380,17 +313,9 @@ var ShellUserVerifier = class { + } + + this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, +- (params, error) => { +- if (!error && params) { +- const [device] = params; +- const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system, +- 'net.reactivated.Fprint', +- device); +- const fprintDeviceType = fprintDeviceProxy['scan-type']; +- +- this._fingerprintReaderType = fprintDeviceType === 'swipe' +- ? FingerprintReaderType.SWIPE +- : FingerprintReaderType.PRESS; ++ (device, error) => { ++ if (!error && device) { ++ this._haveFingerprintReader = true; + this._updateDefaultService(); + } + }); +@@ -423,13 +348,12 @@ var ShellUserVerifier = class { + } + } + +- _reportInitError(where, error, serviceName) { ++ _reportInitError(where, error) { + logError(error, where); + this._hold.release(); + +- this._queueMessage(serviceName, _('Authentication error'), MessageType.ERROR); +- this._failCounter++; +- this._verificationFailed(serviceName, false); ++ this._queueMessage(_("Authentication error"), MessageType.ERROR); ++ this._verificationFailed(false); + } + + async _openReauthenticationChannel(userName) { +@@ -477,35 +401,15 @@ var ShellUserVerifier = class { + } + + _connectSignals() { +- this._disconnectSignals(); +- this._signalIds = []; +- +- let id = this._userVerifier.connect('info', this._onInfo.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('problem', this._onProblem.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('info-query', this._onInfoQuery.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('secret-info-query', this._onSecretInfoQuery.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('conversation-stopped', this._onConversationStopped.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('service-unavailable', this._onServiceUnavailable.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('reset', this._onReset.bind(this)); +- this._signalIds.push(id); +- id = this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); +- this._signalIds.push(id); ++ this._userVerifier.connect('info', this._onInfo.bind(this)); ++ this._userVerifier.connect('problem', this._onProblem.bind(this)); ++ this._userVerifier.connect('info-query', this._onInfoQuery.bind(this)); ++ this._userVerifier.connect('secret-info-query', this._onSecretInfoQuery.bind(this)); ++ this._userVerifier.connect('conversation-stopped', this._onConversationStopped.bind(this)); ++ this._userVerifier.connect('reset', this._onReset.bind(this)); ++ this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); + } + +- _disconnectSignals() { +- if (!this._signalIds || !this._userVerifier) +- return; +- +- this._signalIds.forEach(s => this._userVerifier.disconnect(s)); +- this._signalIds = []; +- } +- + _getForegroundService() { + if (this._preemptingService) + return this._preemptingService; +@@ -521,17 +425,12 @@ var ShellUserVerifier = class { + return serviceName == this._defaultService; + } + +- serviceIsFingerprint(serviceName) { +- return this._fingerprintReaderType !== FingerprintReaderType.NONE && +- serviceName === FINGERPRINT_SERVICE_NAME; +- } +- + _updateDefaultService() { + 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._fingerprintReaderType !== FingerprintReaderType.NONE) ++ else if (this._haveFingerprintReader) + this._defaultService = FINGERPRINT_SERVICE_NAME; + + if (!this._defaultService) { +@@ -553,15 +452,9 @@ var ShellUserVerifier = class { + } catch (e) { + if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + return; +- if (!this.serviceIsForeground(serviceName)) { +- logError(e, 'Failed to start %s for %s'.format(serviceName, this._userName)); +- this._hold.release(); +- return; +- } + this._reportInitError(this._userName +- ? 'Failed to start %s verification for user'.format(serviceName) +- : 'Failed to start %s verification'.format(serviceName), e, +- serviceName); ++ ? 'Failed to start verification for user' ++ : 'Failed to start verification', e); + return; + } + this._hold.release(); +@@ -570,67 +463,30 @@ var ShellUserVerifier = class { + _beginVerification() { + this._startService(this._getForegroundService()); + +- if (this._userName && +- this._fingerprintReaderType !== FingerprintReaderType.NONE && +- !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) ++ if (this._userName && this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) + this._startService(FINGERPRINT_SERVICE_NAME); + } + + _onInfo(client, serviceName, info) { + if (this.serviceIsForeground(serviceName)) { +- this._queueMessage(serviceName, info, MessageType.INFO); +- } else if (this.serviceIsFingerprint(serviceName)) { ++ this._queueMessage(info, MessageType.INFO); ++ } else if (serviceName == FINGERPRINT_SERVICE_NAME && ++ this._haveFingerprintReader) { + // We don't show fingerprint messages directly since it's + // not the main auth service. Instead we use the messages + // as a cue to display our own message. +- if (this._fingerprintReaderType === FingerprintReaderType.SWIPE) { +- // Translators: this message is shown below the password entry field +- // to indicate the user can swipe their finger on the fingerprint reader +- this._queueMessage(serviceName, _('(or swipe finger across reader)'), +- MessageType.HINT); +- } else { +- // Translators: this message is shown below the password entry field +- // to indicate the user can place their finger on the fingerprint reader instead +- this._queueMessage(serviceName, _('(or place finger on reader)'), +- MessageType.HINT); +- } ++ ++ // Translators: this message is shown below the password entry field ++ // to indicate the user can swipe their finger instead ++ this._queueMessage(_("(or swipe finger)"), MessageType.HINT); + } + } + + _onProblem(client, serviceName, problem) { +- const isFingerprint = this.serviceIsFingerprint(serviceName); +- +- if (!this.serviceIsForeground(serviceName) && !isFingerprint) ++ if (!this.serviceIsForeground(serviceName)) + return; + +- this._queuePriorityMessage(serviceName, problem, MessageType.ERROR); +- +- if (isFingerprint) { +- // pam_fprintd allows the user to retry multiple (maybe even infinite! +- // times before failing the authentication conversation. +- // We don't want this behavior to bypass the max-tries setting the user has set, +- // so we count the problem messages to know how many times the user has failed. +- // Once we hit the max number of failures we allow, it's time to failure the +- // conversation from our side. We can't do that right away, however, because +- // we may drop pending messages coming from pam_fprintd. In order to make sure +- // the user sees everything, we queue the failure up to get handled in the +- // near future, after we've finished up the current round of messages. +- this._failCounter++; +- +- if (!this._canRetry()) { +- if (this._fingerprintFailedId) +- GLib.source_remove(this._fingerprintFailedId); +- +- const cancellable = this._cancellable; +- this._fingerprintFailedId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, +- FINGERPRINT_ERROR_TIMEOUT_WAIT, () => { +- this._fingerprintFailedId = 0; +- if (!cancellable.is_cancelled()) +- this._verificationFailed(serviceName, false); +- return GLib.SOURCE_REMOVE; +- }); +- } +- } ++ this._queueMessage(problem, MessageType.ERROR); + } + + _onInfoQuery(client, serviceName, question) { +@@ -659,7 +515,6 @@ var ShellUserVerifier = class { + _onReset() { + // Clear previous attempts to authenticate + this._failCounter = 0; +- this._unavailableServices.clear(); + this._updateDefaultService(); + + this.emit('reset'); +@@ -674,71 +529,46 @@ var ShellUserVerifier = class { + this._onReset(); + } + +- _retry(serviceName) { +- this._hold = new Batch.Hold(); +- this._connectSignals(); +- this._startService(serviceName); ++ _retry() { ++ this.begin(this._userName, new Batch.Hold()); + } + +- _canRetry() { +- return this._userName && +- (this._reauthOnly || this._failCounter < this.allowedFailures); +- } +- +- _verificationFailed(serviceName, shouldRetry) { +- if (serviceName === FINGERPRINT_SERVICE_NAME) { +- if (this._fingerprintFailedId) +- GLib.source_remove(this._fingerprintFailedId); +- } +- ++ _verificationFailed(retry) { + // For Not Listed / enterprise logins, immediately reset + // the dialog + // Otherwise, when in login mode we allow ALLOWED_FAILURES attempts. + // After that, we go back to the welcome screen. +- this._filterServiceMessages(serviceName, MessageType.ERROR); + +- const doneTrying = !shouldRetry || !this._canRetry(); ++ this._failCounter++; ++ let canRetry = retry && this._userName && ++ (this._reauthOnly || ++ this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY)); + +- if (doneTrying) { +- this._disconnectSignals(); +- ++ if (canRetry) { ++ if (!this.hasPendingMessages) { ++ this._retry(); ++ } else { ++ let signalId = this.connect('no-more-messages', () => { ++ this.disconnect(signalId); ++ if (this._cancellable && !this._cancellable.is_cancelled()) ++ this._retry(); ++ }); ++ } ++ } else { + // eslint-disable-next-line no-lonely-if + if (!this.hasPendingMessages) { + this._cancelAndReset(); + } else { +- const cancellable = this._cancellable; + let signalId = this.connect('no-more-messages', () => { + this.disconnect(signalId); +- if (!cancellable.is_cancelled()) +- this._cancelAndReset(); ++ this._cancelAndReset(); + }); + } + } + +- this.emit('verification-failed', serviceName, !doneTrying); +- +- if (!this.hasPendingMessages) { +- this._retry(serviceName); +- } else { +- const cancellable = this._cancellable; +- let signalId = this.connect('no-more-messages', () => { +- this.disconnect(signalId); +- if (!cancellable.is_cancelled()) +- this._retry(serviceName); +- }); +- } ++ this.emit('verification-failed', canRetry); + } + +- _onServiceUnavailable(_client, serviceName, errorMessage) { +- this._unavailableServices.add(serviceName); +- +- if (!errorMessage) +- return; +- +- if (this.serviceIsForeground(serviceName) || this.serviceIsFingerprint(serviceName)) +- this._queueMessage(serviceName, errorMessage, MessageType.ERROR); +- } +- + _onConversationStopped(client, serviceName) { + // If the login failed with the preauthenticated oVirt credentials + // then discard the credentials and revert to default authentication +@@ -748,22 +578,15 @@ var ShellUserVerifier = class { + if (foregroundService) { + this._credentialManagers[foregroundService].token = null; + this._preemptingService = null; +- this._verificationFailed(serviceName, false); ++ this._verificationFailed(false); + return; + } + +- this._filterServiceMessages(serviceName, MessageType.ERROR); +- +- if (this._unavailableServices.has(serviceName)) +- return; +- + // if the password service fails, then cancel everything. + // But if, e.g., fingerprint fails, still give + // password authentication a chance to succeed + if (this.serviceIsForeground(serviceName)) +- this._failCounter++; +- +- this._verificationFailed(serviceName, true); ++ this._verificationFailed(true); + } + }; + Signals.addSignalMethods(ShellUserVerifier.prototype);