[gnome-shell/hotplug: 11/14] mount-operation: implement ask-password for mounting encrypted volumes



commit 01b9773cb6129c9deede43db27a2753bf3c23135
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Wed Jun 22 17:39:01 2011 -0400

    mount-operation: implement ask-password for mounting encrypted volumes
    
    https://bugzilla.gnome.org/show_bug.cgi?id=653520

 data/theme/gnome-shell.css   |    4 ++
 js/ui/automountManager.js    |   16 ++++++-
 js/ui/shellMountOperation.js |  107 ++++++++++++++++++++++++++++++++++++++++--
 src/shell-mount-operation.c  |    3 +-
 4 files changed, 122 insertions(+), 8 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 5325768..d47f651 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -1670,6 +1670,10 @@ StTooltip StLabel {
     icon-size: 48px;
 }
 
+.mount-password-reask {
+    color: red;
+}
+
 .show-processes-dialog,
 .mount-question-dialog {
     spacing: 24px;
diff --git a/js/ui/automountManager.js b/js/ui/automountManager.js
index bdc33b6..4d54c8a 100644
--- a/js/ui/automountManager.js
+++ b/js/ui/automountManager.js
@@ -241,8 +241,15 @@ AutomountManager.prototype = {
         try {
             volume.mount_finish(res);
         } catch (e) {
-            log('Unable to mount volume ' + volume.get_name() + ': ' +
-                e.toString());
+            let string = e.toString();
+
+            // FIXME: needs proper error code handling instead of this
+            // See https://bugzilla.gnome.org/show_bug.cgi?id=591480
+            if (string.indexOf('No key available with this passphrase') != -1)
+                this._reaskPassword(volume);
+            else
+                log('Unable to mount volume ' + volume.get_name() + ': ' + string);
+
             return;
         }
     },
@@ -254,6 +261,11 @@ AutomountManager.prototype = {
             });
     },
 
+    _reaskPassword: function(volume) {
+        let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
+        this._mountVolume(volume, operation.mountOp);        
+    },
+
     _allowAutorun: function(volume) {
         volume.allowAutorun = true;
     },
diff --git a/js/ui/shellMountOperation.js b/js/ui/shellMountOperation.js
index f82f3c4..2c07fca 100644
--- a/js/ui/shellMountOperation.js
+++ b/js/ui/shellMountOperation.js
@@ -8,7 +8,10 @@ const Pango = imports.gi.Pango;
 const St = imports.gi.St;
 const Shell = imports.gi.Shell;
 
+const Main = imports.ui.main;
+const MessageTray = imports.ui.messageTray;
 const ModalDialog = imports.ui.modalDialog;
+const Params = imports.misc.params;
 
 /* ------ Common Utils ------- */
 
@@ -86,12 +89,15 @@ ListItem.prototype = {
 };
 Signals.addSignalMethods(ListItem.prototype);
 
-function ShellMountOperation(source) {
-    this._init(source);
+function ShellMountOperation(source, params) {
+    this._init(source, params);
 }
 
 ShellMountOperation.prototype = {
-    _init: function(source) {
+    _init: function(source, params) {
+        params = Params.parse(params, { reaskPassword: false });
+
+        this._reaskPassword = params.reaskPassword;
         this._initMountOp();
         this._initIcon(source);
     },
@@ -131,8 +137,27 @@ ShellMountOperation.prototype = {
         questionDialog.open(global.get_current_time());
     },
 
-    _onAskPassword: function(op, message, defaultUser, defaultDomain, flags) {
-        // TODO
+    _onAskPassword: function(op, message) {
+        this._notificationShowing = true;
+        this._source = new ShellMountPasswordSource(message, this._icon, this._reaskPassword);
+
+        this._source.connect('password-ready',
+                             Lang.bind(this, function(source, password) {
+                                 this.mountOp.set_password(password);
+                                 this.mountOp.reply(Gio.MountOperationResult.HANDLED);
+
+                                 this._notificationShowing = false;
+                                 this._source.destroy();
+                             }));
+
+        this._source.connect('destroy',
+                             Lang.bind(this, function() {
+                                 if (!this._notificationShowing)
+                                     return;
+
+                                 this._notificationShowing = false;
+                                 this.mountOp.reply(Gio.MountOperationResult.ABORTED);
+                             }));
     },
 
     _onAborted: function(op) {
@@ -222,6 +247,78 @@ ShellMountQuestionDialog.prototype = {
 }
 Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
 
+function ShellMountPasswordSource(message, icon, reaskPassword) {
+    this._init(message, icon, reaskPassword);
+}
+
+ShellMountPasswordSource.prototype = {
+    __proto__: MessageTray.Source.prototype,
+
+    _init: function(message, icon, reaskPassword) {
+        let strings = message.split('\n');
+        MessageTray.Source.prototype._init.call(this, strings[0]);
+
+        this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
+
+        // add ourselves as a source, and popup the notification
+        Main.messageTray.add(this);
+        this.notify(this._notification);
+    },
+}
+Signals.addSignalMethods(ShellMountPasswordSource.prototype);
+
+function ShellMountPasswordNotification(source, strings, icon, reaskPassword) {
+    this._init(source, strings, icon, reaskPassword);
+}
+
+ShellMountPasswordNotification.prototype = {
+    __proto__: MessageTray.Notification.prototype,
+
+    _init: function(source, strings, icon, reaskPassword) {
+        MessageTray.Notification.prototype._init.call(this, source,
+                                                      strings[0], null,
+                                                      { customContent: true,
+                                                        icon: icon });
+
+        // set the notification to transient and urgent, so that it
+        // expands out
+        this.setTransient(true);
+        this.setUrgency(MessageTray.Urgency.CRITICAL);
+
+        if (strings[1])
+            this.addBody(strings[1]);
+
+        this._buildUI(reaskPassword);
+    },
+
+    _buildUI: function(reaskPassword) {
+        if (reaskPassword) {
+            let label = new St.Label({ style_class: 'mount-password-reask',
+                                       text: _("Wrong password, please try again") });
+
+            this.addActor(label);
+        }
+
+        this._responseEntry = new St.Entry({ style_class: 'mount-password-entry',
+                                             can_focus: true });
+        this.setActionArea(this._responseEntry);
+
+        this._responseEntry.clutter_text.connect('activate',
+                                                 Lang.bind(this, this._onEntryActivated));
+        this._responseEntry.clutter_text.set_password_char('\u25cf'); // â U+25CF BLACK CIRCLE
+
+        this._responseEntry.grab_key_focus();
+    },
+
+    _onEntryActivated: function() {
+        let text = this._responseEntry.get_text();
+        if (text == '')
+            return;
+
+        this.source.emit('password-ready', text);
+    }
+}
+
 function ShellProcessesDialog(icon) {
     this._init(icon);
 }
diff --git a/src/shell-mount-operation.c b/src/shell-mount-operation.c
index 0d86ef9..9f172ed 100644
--- a/src/shell-mount-operation.c
+++ b/src/shell-mount-operation.c
@@ -26,7 +26,8 @@
  * object from JS but we can't yet; the default GMountOperation impl
  * automatically calls g_mount_operation_reply(UNHANDLED) after an idle,
  * in interactive methods. We want to handle the reply outselves
- * instead, so we just override the default methods with empty ones.
+ * instead, so we just override the default methods with empty ones,
+ * except for ask-password, as we don't want to handle that.
  *
  * Also, we need to workaround the fact that gjs doesn't support type
  * annotations for signals yet (so we can't effectively forward e.g. 



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