[gnome-initial-setup] Improve keyring handling
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-initial-setup] Improve keyring handling
- Date: Sun, 2 Mar 2014 07:09:37 +0000 (UTC)
commit dd0e394b44092035a7d8a5874c663156e9badae8
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Mar 2 02:06:59 2014 -0500
Improve keyring handling
We're having the problem again where the keyring dialog
pops up when goa tries to save the gmail credentials.
To fix this, ensure that a keyring is present before
we get to the goa page, and prevent keyring dialogs
from appearing by installing a no-op prompter for
gnome-keyring.
configure.ac | 2 +
gnome-initial-setup/Makefile.am | 6 +-
gnome-initial-setup/gis-keyring.c | 127 ++++++++++++
gnome-initial-setup/gis-keyring.h | 34 +++
gnome-initial-setup/gis-prompt.c | 313 +++++++++++++++++++++++++++++
gnome-initial-setup/gis-prompt.h | 51 +++++
gnome-initial-setup/gnome-initial-setup.c | 2 +
gnome-initial-setup/gnome-initial-setup.h | 1 +
8 files changed, 535 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 38050a5..6fa9659 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,8 @@ PKG_CHECK_MODULES(INITIAL_SETUP,
pango >= $PANGO_REQUIRED_VERSION
rest-0.7
json-glib-1.0
+ libsecret-1
+ gcr-3
pwquality)
PKG_CHECK_MODULES(CHEESE,
diff --git a/gnome-initial-setup/Makefile.am b/gnome-initial-setup/Makefile.am
index 8bcd46d..acb80a2 100644
--- a/gnome-initial-setup/Makefile.am
+++ b/gnome-initial-setup/Makefile.am
@@ -6,6 +6,8 @@ uidir = $(datadir)/gnome-initial-setup
AM_CPPFLAGS = \
$(INITIAL_SETUP_CFLAGS) \
+ -DSECRET_API_SUBJECT_TO_CHANGE \
+ -DGCR_API_SUBJECT_TO_CHANGE \
-DUIDIR="\"$(uidir)\"" \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
-DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \
@@ -25,7 +27,9 @@ gnome_initial_setup_SOURCES = \
gnome-initial-setup.c gnome-initial-setup.h \
gis-assistant.c gis-assistant.h \
gis-page.c gis-page.h \
- gis-driver.c gis-driver.h
+ gis-driver.c gis-driver.h \
+ gis-keyring.c gis-keyring.h \
+ gis-prompt.c gis-prompt.h
gnome_initial_setup_LDADD = \
pages/language/libgislanguage.la \
diff --git a/gnome-initial-setup/gis-keyring.c b/gnome-initial-setup/gis-keyring.c
new file mode 100644
index 0000000..a7de651
--- /dev/null
+++ b/gnome-initial-setup/gis-keyring.c
@@ -0,0 +1,127 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Red Hat
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include "gis-keyring.h"
+
+#include <libsecret/secret.h>
+#include <gcr/gcr.h>
+
+#include "gis-prompt.h"
+
+/* We never want to see a keyring dialog, but we need to make
+ * sure a keyring is present.
+ *
+ * To achieve this, install a prompter for gnome-keyring that
+ * never shows any UI, and create a keyring, if one does not
+ * exist yet.
+ */
+
+#define GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME "org.gnome.keyring.SystemPrompter"
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GcrSystemPrompter *prompter;
+
+ prompter = gcr_system_prompter_new (GCR_SYSTEM_PROMPTER_SINGLE, GIS_TYPE_PROMPT);
+ gcr_system_prompter_register (prompter, connection);
+}
+
+static void
+created_collection (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SecretCollection *collection;
+ GError *error = NULL;
+
+ collection = secret_collection_create_finish (result, &error);
+ if (collection)
+ {
+ g_debug ("Created keyring '%s', %s\n",
+ secret_collection_get_label (collection),
+ secret_collection_get_locked (collection) ? "locked" : "unlocked");
+ g_object_unref (collection);
+ }
+ else
+ {
+ g_warning ("Failed to create keyring: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+got_alias (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SecretCollection *collection;
+
+ collection = secret_collection_for_alias_finish (result, NULL);
+ if (collection)
+ {
+ g_debug ("Found default keyring '%s', %s\n",
+ secret_collection_get_label (collection),
+ secret_collection_get_locked (collection) ? "locked" : "unlocked");
+ g_object_unref (collection);
+ }
+ else
+ {
+ secret_collection_create (NULL, "login", SECRET_COLLECTION_DEFAULT, 0, NULL, created_collection, NULL);
+ }
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_debug ("Got " GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME "\n");
+
+ secret_collection_for_alias (NULL, SECRET_COLLECTION_DEFAULT, SECRET_COLLECTION_NONE, NULL, got_alias,
NULL);
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ g_debug ("Lost " GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME "\n");
+}
+
+void
+gis_ensure_keyring (void)
+{
+ g_bus_own_name (G_BUS_TYPE_SESSION,
+ GCR_DBUS_PROMPTER_SYSTEM_BUS_NAME,
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL, NULL);
+}
+
diff --git a/gnome-initial-setup/gis-keyring.h b/gnome-initial-setup/gis-keyring.h
new file mode 100644
index 0000000..607417f
--- /dev/null
+++ b/gnome-initial-setup/gis-keyring.h
@@ -0,0 +1,34 @@
+
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Red Hat
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GIS_KEYRING_H__
+#define __GIS_KEYRING_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void gis_ensure_keyring (void);
+
+G_END_DECLS
+
+#endif /* __GIS_KEYRING_H__ */
diff --git a/gnome-initial-setup/gis-prompt.c b/gnome-initial-setup/gis-prompt.c
new file mode 100644
index 0000000..d4d5159
--- /dev/null
+++ b/gnome-initial-setup/gis-prompt.c
@@ -0,0 +1,313 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Red Hat
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gis-prompt.h"
+
+#include <gcr/gcr.h>
+
+/* This code is inspired by GcrMockPrompt - we never show any UI,
+ * and just return TRUE for confirmations and "gis" for passwords.
+ */
+
+enum {
+ PROP_0,
+
+ PROP_TITLE,
+ PROP_MESSAGE,
+ PROP_DESCRIPTION,
+ PROP_WARNING,
+ PROP_PASSWORD_NEW,
+ PROP_PASSWORD_STRENGTH,
+ PROP_CHOICE_LABEL,
+ PROP_CHOICE_CHOSEN,
+ PROP_CALLER_WINDOW,
+ PROP_CONTINUE_LABEL,
+ PROP_CANCEL_LABEL
+};
+
+static void gis_prompt_iface (GcrPromptIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GisPrompt, gis_prompt, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCR_TYPE_PROMPT, gis_prompt_iface))
+
+static void
+property_free (gpointer data)
+{
+ GParameter *param = data;
+ g_value_unset (¶m->value);
+ g_free (param);
+}
+
+static void
+blank_string_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_STRING);
+ g_value_set_string (¶m->value, "");
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+static void
+blank_boolean_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (¶m->value, FALSE);
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+static void
+blank_int_property (GHashTable *properties,
+ const gchar *property)
+{
+ GParameter *param;
+
+ param = g_new0 (GParameter, 1);
+ param->name = property;
+ g_value_init (¶m->value, G_TYPE_INT);
+ g_value_set_int (¶m->value, 0);
+ g_hash_table_insert (properties, (gpointer)param->name, param);
+}
+
+static void
+gis_prompt_init (GisPrompt *self)
+{
+ self->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, property_free);
+
+ blank_string_property (self->properties, "title");
+ blank_string_property (self->properties, "message");
+ blank_string_property (self->properties, "description");
+ blank_string_property (self->properties, "warning");
+ blank_string_property (self->properties, "choice-label");
+ blank_string_property (self->properties, "caller-window");
+ blank_string_property (self->properties, "continue-label");
+ blank_string_property (self->properties, "cancel-label");
+
+ blank_boolean_property (self->properties, "choice-chosen");
+ blank_boolean_property (self->properties, "password-new");
+
+ blank_int_property (self->properties, "password-strength");
+}
+
+static void
+gis_prompt_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GisPrompt *self = GIS_PROMPT (obj);
+ GParameter *param;
+
+ switch (prop_id) {
+ case PROP_TITLE:
+ case PROP_MESSAGE:
+ case PROP_DESCRIPTION:
+ case PROP_WARNING:
+ case PROP_PASSWORD_NEW:
+ case PROP_CHOICE_LABEL:
+ case PROP_CHOICE_CHOSEN:
+ case PROP_CALLER_WINDOW:
+ case PROP_CONTINUE_LABEL:
+ case PROP_CANCEL_LABEL:
+ param = g_new0 (GParameter, 1);
+ param->name = pspec->name;
+ g_value_init (¶m->value, pspec->value_type);
+ g_value_copy (value, ¶m->value);
+ g_hash_table_replace (self->properties, (gpointer)param->name, param);
+ g_object_notify (G_OBJECT (self), param->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gis_prompt_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GisPrompt *self = GIS_PROMPT (obj);
+ GParameter *param;
+
+ switch (prop_id) {
+ case PROP_TITLE:
+ case PROP_MESSAGE:
+ case PROP_DESCRIPTION:
+ case PROP_WARNING:
+ case PROP_PASSWORD_NEW:
+ case PROP_PASSWORD_STRENGTH:
+ case PROP_CHOICE_LABEL:
+ case PROP_CHOICE_CHOSEN:
+ case PROP_CALLER_WINDOW:
+ case PROP_CONTINUE_LABEL:
+ case PROP_CANCEL_LABEL:
+ param = g_hash_table_lookup (self->properties, pspec->name);
+ g_return_if_fail (param != NULL);
+ g_value_copy (¶m->value, value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gis_prompt_finalize (GObject *obj)
+{
+ GisPrompt *self = GIS_PROMPT (obj);
+
+ g_hash_table_destroy (self->properties);
+
+ G_OBJECT_CLASS (gis_prompt_parent_class)->finalize (obj);
+}
+
+static void
+gis_prompt_class_init (GisPromptClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->get_property = gis_prompt_get_property;
+ gobject_class->set_property = gis_prompt_set_property;
+ gobject_class->finalize = gis_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_CALLER_WINDOW, "caller-window");
+ 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_PASSWORD_NEW, "password-new");
+ g_object_class_override_property (gobject_class, PROP_PASSWORD_STRENGTH, "password-strength");
+ g_object_class_override_property (gobject_class, PROP_CONTINUE_LABEL, "continue-label");
+ g_object_class_override_property (gobject_class, PROP_CANCEL_LABEL, "cancel-label");
+}
+
+static gboolean
+on_timeout_complete (gpointer data)
+{
+ GSimpleAsyncResult *res = data;
+ g_simple_async_result_complete (res);
+ return FALSE;
+}
+
+static void
+destroy_unref_source (gpointer source)
+{
+ if (!g_source_is_destroyed (source))
+ g_source_destroy (source);
+ g_source_unref (source);
+}
+
+static void
+gis_prompt_confirm_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GisPrompt *self = GIS_PROMPT (prompt);
+ GSourceFunc complete_func = on_timeout_complete;
+ GSimpleAsyncResult *res;
+ GSource *source;
+ guint delay_msec;
+
+ res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
+ gis_prompt_confirm_async);
+ g_simple_async_result_set_op_res_gboolean (res, TRUE);
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, on_timeout_complete, g_object_ref (res), g_object_unref);
+ g_source_attach (source, NULL);
+ g_object_set_data_full (G_OBJECT (self), "delay-source", source, destroy_unref_source);
+
+ g_object_unref (res);
+}
+
+static GcrPromptReply
+gis_prompt_confirm_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gis_prompt_confirm_async), GCR_PROMPT_REPLY_CANCEL);
+
+ return g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)) ?
+ GCR_PROMPT_REPLY_CONTINUE : GCR_PROMPT_REPLY_CANCEL;
+}
+
+
+static void
+gis_prompt_password_async (GcrPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GisPrompt *self = GIS_PROMPT (prompt);
+ GSourceFunc complete_func = on_timeout_complete;
+ GSimpleAsyncResult *res;
+ GSource *source;
+ guint delay_msec;
+
+ res = g_simple_async_result_new (G_OBJECT (prompt), callback, user_data,
+ gis_prompt_password_async);
+
+ g_simple_async_result_set_op_res_gpointer (res, "gis", NULL);
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, on_timeout_complete, g_object_ref (res), g_object_unref);
+ g_source_attach (source, NULL);
+ g_object_set_data_full (G_OBJECT (self), "delay-source", source, destroy_unref_source);
+
+ g_object_unref (res);
+}
+
+static const gchar *
+gis_prompt_password_finish (GcrPrompt *prompt,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (prompt),
+ gis_prompt_password_async), NULL);
+
+ return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+}
+
+static void
+gis_prompt_iface (GcrPromptIface *iface)
+{
+ iface->prompt_confirm_async = gis_prompt_confirm_async;
+ iface->prompt_confirm_finish = gis_prompt_confirm_finish;
+ iface->prompt_password_async = gis_prompt_password_async;
+ iface->prompt_password_finish = gis_prompt_password_finish;
+}
diff --git a/gnome-initial-setup/gis-prompt.h b/gnome-initial-setup/gis-prompt.h
new file mode 100644
index 0000000..92353ac
--- /dev/null
+++ b/gnome-initial-setup/gis-prompt.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (C) 2014 Red Hat
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by:
+ * Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GIS_PROMPT_H__
+#define __GIS_PROMPT_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GType gis_prompt_get_type (void) G_GNUC_CONST;
+#define GIS_TYPE_PROMPT (gis_prompt_get_type ())
+#define GIS_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIS_TYPE_PROMPT, GisPrompt))
+#define GIS_IS_PROMPT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIS_TYPE_PROMPT))
+#define GIS_IS_PROMPT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIS_TYPE_PROMPT))
+#define GIS_PROMPT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIS_TYPE_PROMPT, GisPromptClass))
+#define GIS_PROMPT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIS_TYPE_PROMPT, GisPromptClass))
+
+typedef struct _GisPrompt GisPrompt;
+typedef struct _GisPromptClass GisPromptClass;
+
+struct _GisPrompt {
+ GObject parent;
+ GHashTable *properties;
+};
+
+struct _GisPromptClass {
+ GObjectClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GIS_PROMPT_H__ */
diff --git a/gnome-initial-setup/gnome-initial-setup.c b/gnome-initial-setup/gnome-initial-setup.c
index 32eee26..b159c9c 100644
--- a/gnome-initial-setup/gnome-initial-setup.c
+++ b/gnome-initial-setup/gnome-initial-setup.c
@@ -217,6 +217,8 @@ main (int argc, char *argv[])
}
#endif
+ gis_ensure_keyring ();
+
driver = gis_driver_new (get_mode ());
g_signal_connect (driver, "rebuild-pages", G_CALLBACK (rebuild_pages_cb), NULL);
status = g_application_run (G_APPLICATION (driver), argc, argv);
diff --git a/gnome-initial-setup/gnome-initial-setup.h b/gnome-initial-setup/gnome-initial-setup.h
index ebfe6c6..6dce853 100644
--- a/gnome-initial-setup/gnome-initial-setup.h
+++ b/gnome-initial-setup/gnome-initial-setup.h
@@ -33,6 +33,7 @@ typedef struct _GisPage GisPage;
#include "gis-driver.h"
#include "gis-assistant.h"
#include "gis-page.h"
+#include "gis-keyring.h"
#endif /* __GNOME_INITIAL_SETUP_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]