Add gnome-keyring prompter
* Add a keyring prompter based on GcrSystemPrompter * Adds dependency on gcr version 3.3.5 or higher * Not yet using unmerged support for non-pageable memory https://bugzilla.gnome.org/show_bug.cgi?id=652459
This commit is contained in:
parent
72c486cb3e
commit
3ee07d0e82
@ -74,6 +74,7 @@ TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
GCR_MIN_VERSION=3.3.5
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
@ -93,7 +94,8 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||
libnm-glib libnm-util gnome-keyring-1)
|
||||
libnm-glib libnm-util gnome-keyring-1
|
||||
gcr-3 >= $GCR_MIN_VERSION)
|
||||
|
||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
|
||||
|
@ -1979,6 +1979,10 @@ StScrollBar StButton#vhandle:hover
|
||||
spacing-rows: 15px;
|
||||
}
|
||||
|
||||
.keyring-dialog-control-table {
|
||||
spacing-rows: 15px;
|
||||
}
|
||||
|
||||
/* Magnifier */
|
||||
|
||||
.magnifier-zoom-region {
|
||||
|
@ -56,6 +56,7 @@ nobase_dist_js_DATA = \
|
||||
ui/flashspot.js \
|
||||
ui/iconGrid.js \
|
||||
ui/keyboard.js \
|
||||
ui/keyringPrompt.js \
|
||||
ui/layout.js \
|
||||
ui/lightbox.js \
|
||||
ui/link.js \
|
||||
|
207
js/ui/keyringPrompt.js
Normal file
207
js/ui/keyringPrompt.js
Normal file
@ -0,0 +1,207 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gcr = imports.gi.Gcr;
|
||||
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const CheckBox = imports.ui.checkBox;
|
||||
|
||||
let prompter = null;
|
||||
|
||||
const KeyringDialog = new Lang.Class({
|
||||
Name: 'KeyringDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
|
||||
_init: function() {
|
||||
this.parent({ styleClass: 'prompt-dialog' });
|
||||
|
||||
this.prompt = new Shell.KeyringPrompt();
|
||||
this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
|
||||
this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
|
||||
this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
|
||||
|
||||
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||
vertical: false });
|
||||
this.contentLayout.add(mainContentBox);
|
||||
|
||||
let icon = new St.Icon({ icon_name: 'dialog-password-symbolic' });
|
||||
mainContentBox.add(icon,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||
vertical: true });
|
||||
mainContentBox.add(this._messageBox,
|
||||
{ y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
|
||||
|
||||
let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
|
||||
this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this._messageBox.add(subject,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let description = new St.Label({ style_class: 'prompt-dialog-description' });
|
||||
description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
description.clutter_text.line_wrap = true;
|
||||
this.prompt.bind_property('description', description, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
this._messageBox.add(description,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._controlTable = null;
|
||||
|
||||
let buttons = [{ label: '',
|
||||
action: Lang.bind(this, this._onCancelButton),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: '',
|
||||
action: Lang.bind(this, this._onContinueButton)
|
||||
}]
|
||||
|
||||
this.setButtons(buttons);
|
||||
this._cancelButton = buttons[0].button;
|
||||
this._continueButton = buttons[1].button;
|
||||
|
||||
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||
},
|
||||
|
||||
_buildControlTable: function() {
|
||||
let table = new St.Table({ style_class: 'keyring-dialog-control-table' });
|
||||
let row = 0;
|
||||
|
||||
if (this.prompt.password_visible) {
|
||||
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||
label.set_text(_("Password:"));
|
||||
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: '',
|
||||
can_focus: true});
|
||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
|
||||
table.add(this._passwordEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
||||
row++;
|
||||
} else {
|
||||
this._passwordEntry = null;
|
||||
}
|
||||
|
||||
if (this.prompt.confirm_visible) {
|
||||
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||
label.set_text(_("Type again:"));
|
||||
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: '',
|
||||
can_focus: true});
|
||||
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
||||
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
|
||||
table.add(this._confirmEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
||||
row++;
|
||||
} else {
|
||||
this._confirmEntry = null;
|
||||
}
|
||||
|
||||
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
||||
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
||||
|
||||
if (this.prompt.choice_visible) {
|
||||
let choice = new CheckBox.CheckBox();
|
||||
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
||||
table.add(choice.actor, { row: row, col: 1, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||
row++;
|
||||
}
|
||||
|
||||
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
warning.clutter_text.line_wrap = true;
|
||||
table.add(warning, { row: row, col: 1, x_expand: false, x_fill: false, x_align: St.Align.START });
|
||||
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
if (this._controlTable) {
|
||||
this._controlTable.destroy_all_children();
|
||||
this._controlTable.destroy();
|
||||
}
|
||||
|
||||
this._controlTable = table;
|
||||
this._messageBox.add(table, { x_fill: true, y_fill: true });
|
||||
},
|
||||
|
||||
_ensureOpen: function() {
|
||||
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
||||
// already open - it just returns true without side-effects
|
||||
if (this.open())
|
||||
return true;
|
||||
|
||||
// The above fail if e.g. unable to get input grab
|
||||
//
|
||||
// In an ideal world this wouldn't happen (because the
|
||||
// Shell is in complete control of the session) but that's
|
||||
// just not how things work right now.
|
||||
|
||||
log('keyringPrompt: Failed to show modal dialog.' +
|
||||
' Dismissing prompt request');
|
||||
this.prompt.cancel()
|
||||
return false;
|
||||
},
|
||||
|
||||
_onShowPassword: function(prompt) {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._passwordEntry.grab_key_focus();
|
||||
},
|
||||
|
||||
_onShowConfirm: function(prompt) {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._continueButton.grab_key_focus();
|
||||
},
|
||||
|
||||
_onHidePrompt: function(prompt) {
|
||||
this.close();
|
||||
},
|
||||
|
||||
_onPasswordActivate: function() {
|
||||
if (this.prompt.confirm_visible)
|
||||
this._confirmEntry.grab_key_focus();
|
||||
else
|
||||
this._onContinueButton();
|
||||
},
|
||||
|
||||
_onConfirmActivate: function() {
|
||||
this._onContinueButton();
|
||||
},
|
||||
|
||||
_onContinueButton: function() {
|
||||
this.prompt.complete()
|
||||
},
|
||||
|
||||
_onCancelButton: function() {
|
||||
this.prompt.cancel()
|
||||
},
|
||||
});
|
||||
|
||||
function init() {
|
||||
prompter = new Gcr.SystemPrompter();
|
||||
prompter.connect('new-prompt', function(prompter) {
|
||||
let dialog = new KeyringDialog();
|
||||
return dialog.prompt;
|
||||
});
|
||||
|
||||
let connection = Gio.DBus.session;
|
||||
prompter.register(connection);
|
||||
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
|
||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
}
|
@ -15,6 +15,7 @@ const AutorunManager = imports.ui.autorunManager;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||
const KeyringPrompt = imports.ui.keyringPrompt;
|
||||
const Environment = imports.ui.environment;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const Keyboard = imports.ui.keyboard;
|
||||
@ -232,6 +233,9 @@ function start() {
|
||||
// Attempt to become a PolicyKit authentication agent
|
||||
PolkitAuthenticationAgent.init()
|
||||
|
||||
// Become a prompter for gnome keyring
|
||||
KeyringPrompt.init();
|
||||
|
||||
_startDate = new Date();
|
||||
|
||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||
|
@ -155,6 +155,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-generic-container.c \
|
||||
shell-gtk-embed.c \
|
||||
shell-global.c \
|
||||
shell-keyring-prompt.h \
|
||||
shell-keyring-prompt.c \
|
||||
shell-mobile-providers.c \
|
||||
shell-mount-operation.c \
|
||||
shell-network-agent.c \
|
||||
|
745
src/shell-keyring-prompt.c
Normal file
745
src/shell-keyring-prompt.c
Normal file
@ -0,0 +1,745 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright 2012 Red Hat, Inc.
|
||||
* 2012 Stef Walter <stefw@gnome.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Author: Stef Walter <stefw@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-keyring-prompt.h"
|
||||
|
||||
#define GCR_API_SUBJECT_TO_CHANGE
|
||||
#include <gcr/gcr-base.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef struct _ShellPasswordPromptClass ShellPasswordPromptClass;
|
||||
typedef struct _ShellPasswordPromptPrivate ShellPasswordPromptPrivate;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROMPTING_NONE,
|
||||
PROMPTING_FOR_CONFIRM,
|
||||
PROMPTING_FOR_PASSWORD
|
||||
} PromptingMode;
|
||||
|
||||
struct _ShellKeyringPrompt
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
gchar *title;
|
||||
gchar *message;
|
||||
gchar *description;
|
||||
gchar *warning;
|
||||
gchar *choice_label;
|
||||
gboolean choice_chosen;
|
||||
gboolean password_new;
|
||||
guint password_strength;
|
||||
gchar *continue_label;
|
||||
gchar *cancel_label;
|
||||
|
||||
GcrPromptReply last_reply;
|
||||
GSimpleAsyncResult *async_result;
|
||||
ClutterText *password_actor;
|
||||
ClutterText *confirm_actor;
|
||||
PromptingMode mode;
|
||||
gboolean shown;
|
||||
};
|
||||
|
||||
typedef struct _ShellKeyringPromptClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
} ShellKeyringPromptClass;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TITLE,
|
||||
PROP_MESSAGE,
|
||||
PROP_DESCRIPTION,
|
||||
PROP_WARNING,
|
||||
PROP_CHOICE_LABEL,
|
||||
PROP_CHOICE_CHOSEN,
|
||||
PROP_PASSWORD_NEW,
|
||||
PROP_PASSWORD_STRENGTH,
|
||||
PROP_CALLER_WINDOW,
|
||||
PROP_CONTINUE_LABEL,
|
||||
PROP_CANCEL_LABEL,
|
||||
PROP_PASSWORD_VISIBLE,
|
||||
PROP_CONFIRM_VISIBLE,
|
||||
PROP_WARNING_VISIBLE,
|
||||
PROP_CHOICE_VISIBLE,
|
||||
PROP_PASSWORD_ACTOR,
|
||||
PROP_CONFIRM_ACTOR
|
||||
};
|
||||
|
||||
static void shell_keyring_prompt_iface (GcrPromptIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ShellKeyringPrompt, shell_keyring_prompt, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, shell_keyring_prompt_iface);
|
||||
);
|
||||
|
||||
enum {
|
||||
SIGNAL_SHOW_PASSWORD,
|
||||
SIGNAL_SHOW_CONFIRM,
|
||||
SIGNAL_HIDE_PROMPT,
|
||||
SIGNAL_LAST
|
||||
};
|
||||
|
||||
static gint signals[SIGNAL_LAST];
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_init (ShellKeyringPrompt *self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_set_property (GObject *obj,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_TITLE:
|
||||
g_free (self->title);
|
||||
self->title = g_value_dup_string (value);
|
||||
g_object_notify (obj, "title");
|
||||
break;
|
||||
case PROP_MESSAGE:
|
||||
g_free (self->message);
|
||||
self->message = g_value_dup_string (value);
|
||||
g_object_notify (obj, "message");
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
g_free (self->description);
|
||||
self->description = g_value_dup_string (value);
|
||||
g_object_notify (obj, "description");
|
||||
break;
|
||||
case PROP_WARNING:
|
||||
g_free (self->warning);
|
||||
self->warning = g_value_dup_string (value);
|
||||
if (!self->warning)
|
||||
self->warning = g_strdup ("");
|
||||
g_object_notify (obj, "warning");
|
||||
g_object_notify (obj, "warning-visible");
|
||||
break;
|
||||
case PROP_CHOICE_LABEL:
|
||||
g_free (self->choice_label);
|
||||
self->choice_label = g_value_dup_string (value);
|
||||
if (!self->choice_label)
|
||||
self->choice_label = g_strdup ("");
|
||||
g_object_notify (obj, "choice-label");
|
||||
g_object_notify (obj, "choice-visible");
|
||||
break;
|
||||
case PROP_CHOICE_CHOSEN:
|
||||
self->choice_chosen = g_value_get_boolean (value);
|
||||
g_object_notify (obj, "choice-chosen");
|
||||
break;
|
||||
case PROP_PASSWORD_NEW:
|
||||
self->password_new = g_value_get_boolean (value);
|
||||
g_object_notify (obj, "password-new");
|
||||
g_object_notify (obj, "confirm-visible");
|
||||
break;
|
||||
case PROP_CALLER_WINDOW:
|
||||
/* ignored */
|
||||
break;
|
||||
case PROP_CONTINUE_LABEL:
|
||||
g_free (self->continue_label);
|
||||
self->continue_label = g_value_dup_string (value);
|
||||
g_object_notify (obj, "continue-label");
|
||||
break;
|
||||
case PROP_CANCEL_LABEL:
|
||||
g_free (self->cancel_label);
|
||||
self->cancel_label = g_value_dup_string (value);
|
||||
g_object_notify (obj, "cancel-label");
|
||||
break;
|
||||
case PROP_PASSWORD_ACTOR:
|
||||
shell_keyring_prompt_set_password_actor (self, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_CONFIRM_ACTOR:
|
||||
shell_keyring_prompt_set_confirm_actor (self, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_get_property (GObject *obj,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, self->title ? self->title : "");
|
||||
break;
|
||||
case PROP_MESSAGE:
|
||||
g_value_set_string (value, self->message ? self->message : "");
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
g_value_set_string (value, self->description ? self->description : "");
|
||||
break;
|
||||
case PROP_WARNING:
|
||||
g_value_set_string (value, self->warning ? self->warning : "");
|
||||
break;
|
||||
case PROP_CHOICE_LABEL:
|
||||
g_value_set_string (value, self->choice_label ? self->choice_label : "");
|
||||
break;
|
||||
case PROP_CHOICE_CHOSEN:
|
||||
g_value_set_boolean (value, self->choice_chosen);
|
||||
break;
|
||||
case PROP_PASSWORD_NEW:
|
||||
g_value_set_boolean (value, self->password_new);
|
||||
break;
|
||||
case PROP_PASSWORD_STRENGTH:
|
||||
g_value_set_int (value, self->password_strength);
|
||||
break;
|
||||
case PROP_CALLER_WINDOW:
|
||||
g_value_set_string (value, "");
|
||||
break;
|
||||
case PROP_CONTINUE_LABEL:
|
||||
g_value_set_string (value, self->continue_label);
|
||||
break;
|
||||
case PROP_CANCEL_LABEL:
|
||||
g_value_set_string (value, self->cancel_label);
|
||||
break;
|
||||
case PROP_PASSWORD_VISIBLE:
|
||||
g_value_set_boolean (value, self->mode == PROMPTING_FOR_PASSWORD);
|
||||
break;
|
||||
case PROP_CONFIRM_VISIBLE:
|
||||
g_value_set_boolean (value, self->password_new &&
|
||||
self->mode == PROMPTING_FOR_PASSWORD);
|
||||
break;
|
||||
case PROP_WARNING_VISIBLE:
|
||||
g_value_set_boolean (value, self->warning && self->warning[0]);
|
||||
break;
|
||||
case PROP_CHOICE_VISIBLE:
|
||||
g_value_set_boolean (value, self->choice_label && self->choice_label[0]);
|
||||
break;
|
||||
case PROP_PASSWORD_ACTOR:
|
||||
g_value_set_object (value, shell_keyring_prompt_get_password_actor (self));
|
||||
break;
|
||||
case PROP_CONFIRM_ACTOR:
|
||||
g_value_set_object (value, shell_keyring_prompt_get_confirm_actor (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_dispose (GObject *obj)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
|
||||
|
||||
if (self->shown) {
|
||||
self->shown = FALSE;
|
||||
g_signal_emit (self, signals[SIGNAL_HIDE_PROMPT], 0);
|
||||
}
|
||||
|
||||
if (self->async_result)
|
||||
shell_keyring_prompt_cancel (self);
|
||||
g_assert (self->async_result == NULL);
|
||||
|
||||
shell_keyring_prompt_set_password_actor (self, NULL);
|
||||
shell_keyring_prompt_set_confirm_actor (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (shell_keyring_prompt_parent_class)->dispose (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_finalize (GObject *obj)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (obj);
|
||||
|
||||
g_free (self->title);
|
||||
g_free (self->message);
|
||||
g_free (self->description);
|
||||
g_free (self->warning);
|
||||
g_free (self->choice_label);
|
||||
g_free (self->continue_label);
|
||||
g_free (self->cancel_label);
|
||||
|
||||
G_OBJECT_CLASS (shell_keyring_prompt_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_class_init (ShellKeyringPromptClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = shell_keyring_prompt_get_property;
|
||||
gobject_class->set_property = shell_keyring_prompt_set_property;
|
||||
gobject_class->dispose = shell_keyring_prompt_dispose;
|
||||
gobject_class->finalize = shell_keyring_prompt_finalize;
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_TITLE, "title");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_MESSAGE, "message");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_DESCRIPTION, "description");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_WARNING, "warning");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_PASSWORD_NEW, "password-new");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_CHOICE_LABEL, "choice-label");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_CHOICE_CHOSEN, "choice-chosen");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_CALLER_WINDOW, "caller-window");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
|
||||
|
||||
g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:password-visible
|
||||
*
|
||||
* Whether the password entry is visible or not.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PASSWORD_VISIBLE,
|
||||
g_param_spec_boolean ("password-visible", "Password visible", "Password field is visible",
|
||||
FALSE, G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:confirm-visible
|
||||
*
|
||||
* Whether the password confirm entry is visible or not.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CONFIRM_VISIBLE,
|
||||
g_param_spec_boolean ("confirm-visible", "Confirm visible", "Confirm field is visible",
|
||||
FALSE, G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:warning-visible
|
||||
*
|
||||
* Whether the warning label is visible or not.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_WARNING_VISIBLE,
|
||||
g_param_spec_boolean ("warning-visible", "Warning visible", "Warning is visible",
|
||||
FALSE, G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:choice-visible
|
||||
*
|
||||
* Whether the choice check box is visible or not.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CHOICE_VISIBLE,
|
||||
g_param_spec_boolean ("choice-visible", "Choice visible", "Choice is visible",
|
||||
FALSE, G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:password-actor
|
||||
*
|
||||
* Text field for password
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_PASSWORD_ACTOR,
|
||||
g_param_spec_object ("password-actor", "Password actor", "Text field for password",
|
||||
CLUTTER_TYPE_TEXT, G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ShellKeyringPrompt:confirm-actor
|
||||
*
|
||||
* Text field for confirmation password
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_CONFIRM_ACTOR,
|
||||
g_param_spec_object ("confirm-actor", "Confirm actor", "Text field for confirming password",
|
||||
CLUTTER_TYPE_TEXT, G_PARAM_READWRITE));
|
||||
|
||||
signals[SIGNAL_SHOW_PASSWORD] = g_signal_new ("show-password", G_TYPE_FROM_CLASS (klass),
|
||||
0, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
signals[SIGNAL_SHOW_CONFIRM] = g_signal_new ("show-confirm", G_TYPE_FROM_CLASS (klass),
|
||||
0, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
signals[SIGNAL_HIDE_PROMPT] = g_signal_new ("hide-prompt", G_TYPE_FROM_CLASS (klass),
|
||||
0, 0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_password_async (GcrPrompt *prompt,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
|
||||
GObject *obj;
|
||||
|
||||
if (self->async_result != NULL) {
|
||||
g_warning ("this prompt can only show one prompt at a time");
|
||||
return;
|
||||
}
|
||||
|
||||
self->mode = PROMPTING_FOR_PASSWORD;
|
||||
self->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
|
||||
shell_keyring_prompt_password_async);
|
||||
|
||||
obj = G_OBJECT (self);
|
||||
g_object_notify (obj, "password-visible");
|
||||
g_object_notify (obj, "confirm-visible");
|
||||
g_object_notify (obj, "warning-visible");
|
||||
g_object_notify (obj, "choice-visible");
|
||||
|
||||
self->shown = TRUE;
|
||||
g_signal_emit (self, signals[SIGNAL_SHOW_PASSWORD], 0);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
shell_keyring_prompt_password_finish (GcrPrompt *prompt,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
|
||||
shell_keyring_prompt_password_async), NULL);
|
||||
|
||||
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
|
||||
return NULL;
|
||||
|
||||
if (self->last_reply == GCR_PROMPT_REPLY_CONTINUE)
|
||||
return clutter_text_get_text (self->password_actor);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_confirm_async (GcrPrompt *prompt,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
|
||||
GObject *obj;
|
||||
|
||||
if (self->async_result != NULL) {
|
||||
g_warning ("this prompt is already prompting");
|
||||
return;
|
||||
}
|
||||
|
||||
self->mode = PROMPTING_FOR_CONFIRM;
|
||||
self->async_result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
|
||||
shell_keyring_prompt_confirm_async);
|
||||
|
||||
obj = G_OBJECT (self);
|
||||
g_object_notify (obj, "password-visible");
|
||||
g_object_notify (obj, "confirm-visible");
|
||||
g_object_notify (obj, "warning-visible");
|
||||
g_object_notify (obj, "choice-visible");
|
||||
|
||||
self->shown = TRUE;
|
||||
g_signal_emit (self, signals[SIGNAL_SHOW_CONFIRM], 0);
|
||||
}
|
||||
|
||||
static GcrPromptReply
|
||||
shell_keyring_prompt_confirm_finish (GcrPrompt *prompt,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (prompt);
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
|
||||
shell_keyring_prompt_confirm_async), GCR_PROMPT_REPLY_CANCEL);
|
||||
|
||||
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
|
||||
return GCR_PROMPT_REPLY_CANCEL;
|
||||
|
||||
return self->last_reply;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_keyring_prompt_iface (GcrPromptIface *iface)
|
||||
{
|
||||
iface->prompt_password_async = shell_keyring_prompt_password_async;
|
||||
iface->prompt_password_finish = shell_keyring_prompt_password_finish;
|
||||
iface->prompt_confirm_async = shell_keyring_prompt_confirm_async;
|
||||
iface->prompt_confirm_finish = shell_keyring_prompt_confirm_finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_new:
|
||||
*
|
||||
* Create new internal prompt base
|
||||
*
|
||||
* Returns: (transfer full): new internal prompt
|
||||
*/
|
||||
ShellKeyringPrompt *
|
||||
shell_keyring_prompt_new (void)
|
||||
{
|
||||
return g_object_new (SHELL_TYPE_KEYRING_PROMPT, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_get_password_actor:
|
||||
* @self: the internal prompt
|
||||
*
|
||||
* Get the prompt password text actor
|
||||
*
|
||||
* Returns: (transfer none) (allow-none): the password actor
|
||||
*/
|
||||
ClutterText *
|
||||
shell_keyring_prompt_get_password_actor (ShellKeyringPrompt *self)
|
||||
{
|
||||
g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), NULL);
|
||||
return self->password_actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_get_confirm_actor:
|
||||
* @self: the internal prompt
|
||||
*
|
||||
* Get the prompt password text actor
|
||||
*
|
||||
* Returns: (transfer none) (allow-none): the password actor
|
||||
*/
|
||||
ClutterText *
|
||||
shell_keyring_prompt_get_confirm_actor (ShellKeyringPrompt *self)
|
||||
{
|
||||
g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), NULL);
|
||||
return self->confirm_actor;
|
||||
}
|
||||
|
||||
static guint
|
||||
calculate_password_strength (const gchar *password)
|
||||
{
|
||||
int upper, lower, digit, misc;
|
||||
gdouble pwstrength;
|
||||
int length, i;
|
||||
|
||||
/*
|
||||
* This code is based on the Master Password dialog in Firefox
|
||||
* (pref-masterpass.js)
|
||||
* Original code triple-licensed under the MPL, GPL, and LGPL
|
||||
* so is license-compatible with this file
|
||||
*/
|
||||
|
||||
length = strlen (password);
|
||||
|
||||
/* Always return 0 for empty passwords */
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
upper = 0;
|
||||
lower = 0;
|
||||
digit = 0;
|
||||
misc = 0;
|
||||
|
||||
for (i = 0; i < length ; i++)
|
||||
{
|
||||
if (g_ascii_isdigit (password[i]))
|
||||
digit++;
|
||||
else if (g_ascii_islower (password[i]))
|
||||
lower++;
|
||||
else if (g_ascii_isupper (password[i]))
|
||||
upper++;
|
||||
else
|
||||
misc++;
|
||||
}
|
||||
|
||||
if (length > 5)
|
||||
length = 5;
|
||||
if (digit > 3)
|
||||
digit = 3;
|
||||
if (upper > 3)
|
||||
upper = 3;
|
||||
if (misc > 3)
|
||||
misc = 3;
|
||||
|
||||
pwstrength = ((length * 1) - 2) +
|
||||
(digit * 1) +
|
||||
(misc * 1.5) +
|
||||
(upper * 1);
|
||||
|
||||
/* Always return 1+ for non-empty passwords */
|
||||
if (pwstrength < 1.0)
|
||||
pwstrength = 1.0;
|
||||
if (pwstrength > 10.0)
|
||||
pwstrength = 10.0;
|
||||
|
||||
return (guint)pwstrength;
|
||||
}
|
||||
|
||||
static void
|
||||
on_password_changed (ClutterText *text,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellKeyringPrompt *self = SHELL_KEYRING_PROMPT (user_data);
|
||||
const gchar *password;
|
||||
|
||||
password = clutter_text_get_text (self->password_actor);
|
||||
|
||||
self->password_strength = calculate_password_strength (password);
|
||||
g_object_notify (G_OBJECT (self), "password-strength");
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_set_password_actor:
|
||||
* @self: the internal prompt
|
||||
* @password_actor: (allow-none): the password actor
|
||||
*
|
||||
* Set the prompt password text actor
|
||||
*/
|
||||
void
|
||||
shell_keyring_prompt_set_password_actor (ShellKeyringPrompt *self,
|
||||
ClutterText *password_actor)
|
||||
{
|
||||
g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
|
||||
g_return_if_fail (password_actor == NULL || CLUTTER_IS_TEXT (password_actor));
|
||||
|
||||
if (password_actor)
|
||||
{
|
||||
g_signal_connect (password_actor, "text-changed", G_CALLBACK (on_password_changed), self);
|
||||
g_object_ref (password_actor);
|
||||
}
|
||||
if (self->password_actor)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->password_actor, on_password_changed, self);
|
||||
g_object_unref (self->password_actor);
|
||||
}
|
||||
|
||||
self->password_actor = password_actor;
|
||||
g_object_notify (G_OBJECT (self), "password-actor");
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_set_confirm_actor:
|
||||
* @self: the internal prompt
|
||||
* @confirm_actor: (allow-none): the confirm password actor
|
||||
*
|
||||
* Set the prompt password confirmation text actor
|
||||
*/
|
||||
void
|
||||
shell_keyring_prompt_set_confirm_actor (ShellKeyringPrompt *self,
|
||||
ClutterText *confirm_actor)
|
||||
{
|
||||
g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
|
||||
g_return_if_fail (confirm_actor == NULL || CLUTTER_IS_TEXT (confirm_actor));
|
||||
|
||||
if (confirm_actor)
|
||||
g_object_ref (confirm_actor);
|
||||
if (self->confirm_actor)
|
||||
g_object_unref (self->confirm_actor);
|
||||
self->confirm_actor = confirm_actor;
|
||||
g_object_notify (G_OBJECT (self), "confirm-actor");
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_complete:
|
||||
* @self: the internal prompt
|
||||
*
|
||||
* Called by the implementation when the prompt completes. There are various
|
||||
* checks done. %TRUE is returned if the prompt actually should complete.
|
||||
*
|
||||
* Returns: whether the prompt completed
|
||||
*/
|
||||
gboolean
|
||||
shell_keyring_prompt_complete (ShellKeyringPrompt *self)
|
||||
{
|
||||
GSimpleAsyncResult *res;
|
||||
const gchar *password;
|
||||
const gchar *confirm;
|
||||
const gchar *env;
|
||||
|
||||
g_return_val_if_fail (SHELL_IS_KEYRING_PROMPT (self), FALSE);
|
||||
g_return_val_if_fail (self->mode != PROMPTING_NONE, FALSE);
|
||||
g_return_val_if_fail (self->async_result != NULL, FALSE);
|
||||
|
||||
if (self->mode == PROMPTING_FOR_PASSWORD)
|
||||
{
|
||||
password = clutter_text_get_text (self->password_actor);
|
||||
|
||||
/* Is it a new password? */
|
||||
if (self->password_new)
|
||||
{
|
||||
confirm = clutter_text_get_text (self->confirm_actor);
|
||||
|
||||
/* Do the passwords match? */
|
||||
if (!g_str_equal (password, confirm))
|
||||
{
|
||||
gcr_prompt_set_warning (GCR_PROMPT (self), _("Passwords do not match."));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Don't allow blank passwords if in paranoid mode */
|
||||
env = g_getenv ("GNOME_KEYRING_PARANOID");
|
||||
if (env && *env)
|
||||
{
|
||||
gcr_prompt_set_warning (GCR_PROMPT (self), _("Password cannot be blank"));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
self->password_strength = calculate_password_strength (password);
|
||||
g_object_notify (G_OBJECT (self), "password-strength");
|
||||
}
|
||||
|
||||
self->last_reply = GCR_PROMPT_REPLY_CONTINUE;
|
||||
|
||||
res = self->async_result;
|
||||
self->async_result = NULL;
|
||||
self->mode = PROMPTING_NONE;
|
||||
|
||||
g_simple_async_result_complete (res);
|
||||
g_object_unref (res);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_keyring_prompt_cancel:
|
||||
* @self: the internal prompt
|
||||
*
|
||||
* Called by implementation when the prompt is cancelled.
|
||||
*/
|
||||
void
|
||||
shell_keyring_prompt_cancel (ShellKeyringPrompt *self)
|
||||
{
|
||||
GSimpleAsyncResult *res;
|
||||
|
||||
g_return_if_fail (SHELL_IS_KEYRING_PROMPT (self));
|
||||
g_return_if_fail (self->mode != PROMPTING_NONE);
|
||||
g_return_if_fail (self->async_result != NULL);
|
||||
|
||||
self->last_reply = GCR_PROMPT_REPLY_CANCEL;
|
||||
|
||||
res = self->async_result;
|
||||
self->async_result = NULL;
|
||||
self->mode = PROMPTING_NONE;
|
||||
|
||||
g_simple_async_result_complete (res);
|
||||
g_object_unref (res);
|
||||
}
|
59
src/shell-keyring-prompt.h
Normal file
59
src/shell-keyring-prompt.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/* shell-keyring-prompt.c - prompt handler for gnome-keyring-daemon
|
||||
|
||||
Copyright (C) 2011 Stefan Walter
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Author: Stef Walter <stef@thewalter.net>
|
||||
*/
|
||||
|
||||
#ifndef __SHELL_KEYRING_PROMPT_H__
|
||||
#define __SHELL_KEYRING_PROMPT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ShellKeyringPrompt ShellKeyringPrompt;
|
||||
|
||||
#define SHELL_TYPE_KEYRING_PROMPT (shell_keyring_prompt_get_type ())
|
||||
#define SHELL_KEYRING_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_KEYRING_PROMPT, ShellKeyringPrompt))
|
||||
#define SHELL_IS_KEYRING_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_KEYRING_PROMPT))
|
||||
|
||||
GType shell_keyring_prompt_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ShellKeyringPrompt * shell_keyring_prompt_new (void);
|
||||
|
||||
ClutterText * shell_keyring_prompt_get_password_actor (ShellKeyringPrompt *self);
|
||||
|
||||
void shell_keyring_prompt_set_password_actor (ShellKeyringPrompt *self,
|
||||
ClutterText *password_actor);
|
||||
|
||||
ClutterText * shell_keyring_prompt_get_confirm_actor (ShellKeyringPrompt *self);
|
||||
|
||||
void shell_keyring_prompt_set_confirm_actor (ShellKeyringPrompt *self,
|
||||
ClutterText *confirm_actor);
|
||||
|
||||
gboolean shell_keyring_prompt_complete (ShellKeyringPrompt *self);
|
||||
|
||||
void shell_keyring_prompt_cancel (ShellKeyringPrompt *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_KEYRING_PROMPT_H__ */
|
Loading…
Reference in New Issue
Block a user