[gnome-shell] Login/UnlockDialog: don't reset immediately if auth fails



commit db20a54861f141cbbb51e5af786e77c5c3220ef7
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Tue Aug 7 16:49:22 2012 +0200

    Login/UnlockDialog: don't reset immediately if auth fails
    
    Instead of showing a notification, add a small message immediately
    below the entry, and give the user two more attempts to login,
    before going back to the welcome or lock screen.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=682544

 data/theme/gnome-shell.css |    4 ++++
 js/gdm/loginDialog.js      |   18 +++++++++++++-----
 js/gdm/util.js             |   38 +++++++++++++++++++++++++++++++++-----
 js/ui/unlockDialog.js      |   26 +++++++++++++++++---------
 4 files changed, 67 insertions(+), 19 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 98a69dd..ec4eabe 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -2189,6 +2189,10 @@ StButton.popup-menu-item:insensitive {
     background-gradient-end: #74a0d0;
 }
 
+.login-dialog-message-warning {
+    color: orange;
+}
+
 .unlock-dialog-user-name-container {
     spacing: .4em;
 }
diff --git a/js/gdm/loginDialog.js b/js/gdm/loginDialog.js
index 7bedf45..c6ac030 100644
--- a/js/gdm/loginDialog.js
+++ b/js/gdm/loginDialog.js
@@ -647,7 +647,7 @@ const LoginDialog = new Lang.Class({
 
         this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
         this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
-        this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
+        this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
         this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
 
         this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
@@ -715,6 +715,10 @@ const LoginDialog = new Lang.Class({
                               x_fill: true,
                               y_fill: false,
                               x_align: St.Align.START });
+
+        this._promptMessage = new St.Label({ visible: false });
+        this._promptBox.add(this._promptMessage, { x_fill: true });
+
         this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
         this._promptLoginHint.hide();
         this._promptBox.add(this._promptLoginHint);
@@ -797,6 +801,8 @@ const LoginDialog = new Lang.Class({
     },
 
     _onReset: function(client, serviceName) {
+        this._promptMessage.hide();
+
         let tasks = [this._hidePrompt,
 
                      new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
@@ -826,6 +832,12 @@ const LoginDialog = new Lang.Class({
         this._sessionList.setActiveSession(sessionId);
     },
 
+    _showMessage: function(userVerifier, message, styleClass) {
+        this._promptMessage.text = message;
+        this._promptMessage.styleClass = styleClass;
+        GdmUtil.fadeInActor(this._promptMessage);
+    },
+
     _showLoginHint: function(verifier, message) {
         this._promptLoginHint.set_text(message)
         GdmUtil.fadeInActor(this._promptLoginHint);
@@ -1081,10 +1093,6 @@ const LoginDialog = new Lang.Class({
                              }));
     },
 
-    _onVerificationFailed: function() {
-        this._userVerifier.cancel();
-    },
-
     _onNotListedClicked: function(user) {
         let tasks = [function() {
                          return this._userList.hideItems();
diff --git a/js/gdm/util.js b/js/gdm/util.js
index d2e537a..681c0a6 100644
--- a/js/gdm/util.js
+++ b/js/gdm/util.js
@@ -2,6 +2,7 @@
 
 const Gio = imports.gi.Gio;
 const Lang = imports.lang;
+const Mainloop = imports.mainloop;
 const Signals = imports.signals;
 
 const Batch = imports.gdm.batch;
@@ -19,6 +20,7 @@ const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
 const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
 const BANNER_MESSAGE_KEY = 'banner-message-enable';
 const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
+const ALLOWED_FAILURES_KEY = 'allowed-failures';
 
 const LOGO_KEY = 'logo';
 
@@ -81,6 +83,8 @@ const ShellUserVerifier = new Lang.Class({
 
         this._fprintManager = new Fprint.FprintManager();
         this._realmManager = new Realmd.Manager();
+
+        this._failCounter = 0;
     },
 
     begin: function(userName, hold) {
@@ -242,7 +246,7 @@ const ShellUserVerifier = new Lang.Class({
             // to indicate the user can swipe their finger instead
             this.emit('show-login-hint', _("(or swipe finger)"));
         } else if (serviceName == PASSWORD_SERVICE_NAME) {
-            Main.notifyError(info);
+            this.emit('show-message', info, 'login-dialog-message-info');
         }
     },
 
@@ -251,7 +255,7 @@ const ShellUserVerifier = new Lang.Class({
         // users who haven't enrolled their fingerprint.
         if (serviceName != PASSWORD_SERVICE_NAME)
             return;
-        Main.notifyError(problem);
+        this.emit('show-message', problem, 'login-dialog-message-warning');
     },
 
     _showRealmLoginHint: function() {
@@ -290,8 +294,10 @@ const ShellUserVerifier = new Lang.Class({
     },
 
     _onReset: function() {
-        this._userVerifier.run_dispose();
-        this._userVerifier = null;
+        this.clear();
+
+        // Clear previous attempts to authenticate
+        this._failCounter = 0;
 
         this.emit('reset');
     },
@@ -300,12 +306,34 @@ const ShellUserVerifier = new Lang.Class({
         this.emit('verification-complete');
     },
 
+    _verificationFailed: function() {
+        // For Not Listed / enterprise logins, immediately reset
+        // the dialog
+        // Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
+        // go back to the welcome screen.
+
+        if (!this._userName ||
+            (++this._failCounter) == this._settings.get_int(ALLOWED_FAILURES_KEY)) {
+            // Allow some time to see the message, then reset everything
+            Mainloop.timeout_add(3000, Lang.bind(this, function() {
+                this.cancel();
+
+                this._onReset();
+            }));
+        } else {
+            this.clear();
+            this.begin(this._userName, new Batch.Hold());
+        }
+
+        this.emit('verification-failed');
+    },
+
     _onConversationStopped: function(client, serviceName) {
         // if the password service fails, then cancel everything.
         // But if, e.g., fingerprint fails, still give
         // password authentication a chance to succeed
         if (serviceName == PASSWORD_SERVICE_NAME) {
-            this.emit('verification-failed');
+            this._verificationFailed();
         }
 
         this.emit('hide-login-hint');
diff --git a/js/ui/unlockDialog.js b/js/ui/unlockDialog.js
index da10cec..b18c18d 100644
--- a/js/ui/unlockDialog.js
+++ b/js/ui/unlockDialog.js
@@ -89,13 +89,15 @@ const UnlockDialog = new Lang.Class({
         this._userName = GLib.get_user_name();
         this._user = this._userManager.get_user(this._userName);
 
+        this._failCounter = 0;
+
         this._greeterClient = new Gdm.Client();
         this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
 
-        this._userVerifier.connect('reset', Lang.bind(this, this._reset));
         this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
+        this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
         this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
-        this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
+        this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
 
         this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
         this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
@@ -122,6 +124,9 @@ const UnlockDialog = new Lang.Class({
 
         this.contentLayout.add_actor(this._promptLayout);
 
+        this._promptMessage = new St.Label({ visible: false });
+        this.contentLayout.add(this._promptMessage, { x_fill: true });
+
         this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
         this._promptLoginHint.hide();
         this.contentLayout.add_actor(this._promptLoginHint);
@@ -135,7 +140,6 @@ const UnlockDialog = new Lang.Class({
         this.setButtons([cancelButton, this._okButton]);
 
         this._updateOkButton(false);
-        this._reset();
 
         let otherUserLabel = new St.Label({ text: _("Log in as another user"),
                                             style_class: 'login-dialog-not-listed-label' });
@@ -150,6 +154,9 @@ const UnlockDialog = new Lang.Class({
                               { x_align: St.Align.START,
                                 x_fill: false });
 
+        let batch = new Batch.Hold();
+        this._userVerifier.begin(this._userName, batch);
+
         GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
             this.emit('loaded');
             return false;
@@ -165,9 +172,10 @@ const UnlockDialog = new Lang.Class({
         this._okButton.button.reactive = sensitive;
     },
 
-    _reset: function() {
-        this._userVerifier.clear();
-        this._userVerifier.begin(this._userName, new Batch.Hold());
+    _showMessage: function(userVerifier, message, styleClass) {
+        this._promptMessage.text = message;
+        this._promptMessage.styleClass = styleClass;
+        GdmUtil.fadeInActor(this._promptMessage);
     },
 
     _onAskQuestion: function(verifier, serviceName, question, passwordChar) {
@@ -207,13 +215,13 @@ const UnlockDialog = new Lang.Class({
         this.emit('unlocked');
     },
 
-    _onVerificationFailed: function() {
-        this._userVerifier.cancel();
+    _onReset: function() {
         this.emit('failed');
     },
 
     _escape: function() {
-        this._onVerificationFailed();
+        this._userVerifier.cancel();
+        this.emit('failed');
     },
 
     _otherUserClicked: function(button, event) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]