mount-operation: implement ask-password for mounting encrypted volumes

https://bugzilla.gnome.org/show_bug.cgi?id=653520
This commit is contained in:
Cosimo Cecchi 2011-07-12 11:29:49 -04:00
parent 5c1dd4ea18
commit 0b77ea422a
4 changed files with 118 additions and 8 deletions

View File

@ -1678,6 +1678,10 @@ StTooltip StLabel {
icon-size: 48px;
}
.mount-password-reask {
color: red;
}
.show-processes-dialog,
.mount-question-dialog {
spacing: 24px;

View File

@ -178,8 +178,14 @@ 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);
}
},
@ -190,6 +196,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;
},

View File

@ -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;
const LIST_ITEM_ICON_SIZE = 48;
@ -86,12 +89,16 @@ 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._dialog = null;
this._processesDialog = null;
@ -126,8 +133,27 @@ ShellMountOperation.prototype = {
this._dialog.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) {
@ -213,6 +239,74 @@ 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]);
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);
}

View File

@ -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.