[gnome-software/wip/rancell/reviews] Use libsecret for storing Ubuntu One credentials



commit c3d9941dfb0a2c432ae34192831d8bf124a369b0
Author: William Hua <william hua canonical com>
Date:   Mon Feb 22 18:06:09 2016 -0500

    Use libsecret for storing Ubuntu One credentials

 configure.ac                           |    1 +
 src/plugins/Makefile.am                |    9 +-
 src/plugins/gs-plugin-ubuntu-reviews.c |  231 ++++++++++++++++++++++++++++++--
 3 files changed, 227 insertions(+), 14 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 38ba2b8..61806f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,6 +69,7 @@ PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.51.92)
 PKG_CHECK_MODULES(GSETTINGS_DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.11.5)
 PKG_CHECK_MODULES(GNOME_DESKTOP, gnome-desktop-3.0 >= 3.17.92)
 PKG_CHECK_MODULES(OAUTH, oauth)
+PKG_CHECK_MODULES(LIBSECRET, libsecret-1)
 AC_PATH_PROG(APPSTREAM_UTIL, [appstream-util], [unfound])
 AC_ARG_ENABLE(man,
               [AS_HELP_STRING([--enable-man],
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 1c61244..136cec7 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -14,6 +14,7 @@ AM_CPPFLAGS =                                         \
        $(LIMBA_CFLAGS)                                 \
        $(XDG_APP_CFLAGS)                               \
        $(OAUTH_CFLAGS)                                 \
+       $(LIBSECRET_CFLAGS)                             \
        -DBINDIR=\"$(bindir)\"                          \
        -DDATADIR=\"$(datadir)\"                        \
        -DGS_MODULESETDIR=\"$(datadir)/gnome-software/modulesets.d\" \
@@ -165,7 +166,13 @@ libgs_plugin_hardcoded_blacklist_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 libgs_plugin_ubuntu_reviews_la_SOURCES =               \
        gs-plugin-ubuntu-reviews.c                      \
        gs-ubuntu-login-dialog.c
-libgs_plugin_ubuntu_reviews_la_LIBADD = $(GS_PLUGIN_LIBS) $(SOUP_LIBS) $(JSON_GLIB_LIBS) $(OAUTH_LIBS) 
$(SQLITE_LIBS)
+libgs_plugin_ubuntu_reviews_la_LIBADD =                        \
+       $(GS_PLUGIN_LIBS)                               \
+       $(SOUP_LIBS)                                    \
+       $(JSON_GLIB_LIBS)                               \
+       $(OAUTH_LIBS)                                   \
+       $(SQLITE_LIBS)                                  \
+       $(LIBSECRET_LIBS)
 libgs_plugin_ubuntu_reviews_la_LDFLAGS = -module -avoid-version
 libgs_plugin_ubuntu_reviews_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 
diff --git a/src/plugins/gs-plugin-ubuntu-reviews.c b/src/plugins/gs-plugin-ubuntu-reviews.c
index 64e3f81..3712182 100644
--- a/src/plugins/gs-plugin-ubuntu-reviews.c
+++ b/src/plugins/gs-plugin-ubuntu-reviews.c
@@ -27,6 +27,7 @@
 #include <json-glib/json-glib.h>
 #include <oauth.h>
 #include <sqlite3.h>
+#include <libsecret/secret.h>
 
 #include <gs-plugin.h>
 #include <gs-utils.h>
@@ -34,6 +35,12 @@
 #include "gs-ubuntu-login-dialog.h"
 #include "gs-os-release.h"
 
+#define SCHEMA_NAME     "com.ubuntu.UbuntuOne.GnomeSoftware"
+#define CONSUMER_KEY    "consumer-key"
+#define CONSUMER_SECRET "consumer-secret"
+#define TOKEN_KEY       "token-key"
+#define TOKEN_SECRET    "token-secret"
+
 struct GsPluginPrivate {
        gchar           *db_path;
        sqlite3         *db;
@@ -842,6 +849,7 @@ typedef struct
 
        GCond cond;
        GMutex mutex;
+
        gboolean done;
        gboolean success;
        gboolean remember;
@@ -886,40 +894,237 @@ show_login_dialog (gpointer user_data)
        return G_SOURCE_REMOVE;
 }
 
+typedef struct
+{
+       GsPlugin *plugin;
+
+       GCancellable *cancellable;
+       GCond cond;
+       GMutex mutex;
+
+       gint waiting;
+} SecretContext;
+
+static void
+lookup_consumer_key (GObject      *source_object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+       SecretContext *context = user_data;
+
+       context->plugin->priv->consumer_key = secret_password_lookup_finish (result, NULL);
+
+       g_mutex_lock (&context->mutex);
+
+       if (context->plugin->priv->consumer_key != NULL)
+               context->waiting--;
+       else
+               context->waiting = 0;
+
+       g_cond_signal (&context->cond);
+       g_mutex_unlock (&context->mutex);
+}
+
+static void
+lookup_consumer_secret (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+       SecretContext *context = user_data;
+
+       context->plugin->priv->consumer_secret = secret_password_lookup_finish (result, NULL);
+
+       g_mutex_lock (&context->mutex);
+
+       if (context->plugin->priv->consumer_secret != NULL)
+               context->waiting--;
+       else
+               context->waiting = 0;
+
+       g_cond_signal (&context->cond);
+       g_mutex_unlock (&context->mutex);
+}
+
+static void
+lookup_token_key (GObject      *source_object,
+                 GAsyncResult *result,
+                 gpointer      user_data)
+{
+       SecretContext *context = user_data;
+
+       context->plugin->priv->token_key = secret_password_lookup_finish (result, NULL);
+
+       g_mutex_lock (&context->mutex);
+
+       if (context->plugin->priv->token_key != NULL)
+               context->waiting--;
+       else
+               context->waiting = 0;
+
+       g_cond_signal (&context->cond);
+       g_mutex_unlock (&context->mutex);
+}
+
+static void
+lookup_token_secret (GObject      *source_object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+       SecretContext *context = user_data;
+
+       context->plugin->priv->token_secret = secret_password_lookup_finish (result, NULL);
+
+       g_mutex_lock (&context->mutex);
+
+       if (context->plugin->priv->token_secret != NULL)
+               context->waiting--;
+       else
+               context->waiting = 0;
+
+       g_cond_signal (&context->cond);
+       g_mutex_unlock (&context->mutex);
+}
+
 static gboolean
 sign_into_ubuntu (GsPlugin  *plugin,
                  GError   **error)
 {
+       static SecretSchema schema = {
+               SCHEMA_NAME,
+               SECRET_SCHEMA_NONE,
+               { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
+       };
+
        GsPluginPrivate *priv = plugin->priv;
-       LoginContext context = { 0 };
+       SecretContext secret_context = { 0 };
+       LoginContext login_context = { 0 };
 
+       /* Use current credentials if already available */
        if (priv->consumer_key != NULL &&
            priv->consumer_secret != NULL &&
            priv->token_key != NULL &&
            priv->token_secret != NULL)
                return TRUE;
 
+       /* Otherwise start with a clean slate */
        g_clear_pointer (&priv->token_secret, g_free);
        g_clear_pointer (&priv->token_key, g_free);
        g_clear_pointer (&priv->consumer_secret, g_free);
        g_clear_pointer (&priv->consumer_key, g_free);
 
-       context.plugin = plugin;
-       context.error = error;
-       g_cond_init (&context.cond);
-       g_mutex_init (&context.mutex);
-       g_mutex_lock (&context.mutex);
+       /* Use credentials from libsecret if available */
+       secret_context.plugin = plugin;
+       secret_context.waiting = 4;
+       secret_context.cancellable = g_cancellable_new ();
+       g_cond_init (&secret_context.cond);
+       g_mutex_init (&secret_context.mutex);
+       g_mutex_lock (&secret_context.mutex);
+
+       secret_password_lookup (&schema,
+                               secret_context.cancellable,
+                               lookup_consumer_key,
+                               &secret_context,
+                               "key", CONSUMER_KEY,
+                               NULL);
+       secret_password_lookup (&schema,
+                               secret_context.cancellable,
+                               lookup_consumer_secret,
+                               &secret_context,
+                               "key", CONSUMER_SECRET,
+                               NULL);
+       secret_password_lookup (&schema,
+                               secret_context.cancellable,
+                               lookup_token_key,
+                               &secret_context,
+                               "key", TOKEN_KEY,
+                               NULL);
+       secret_password_lookup (&schema,
+                               secret_context.cancellable,
+                               lookup_token_secret,
+                               &secret_context,
+                               "key", TOKEN_SECRET,
+                               NULL);
+
+       while (secret_context.waiting > 0)
+               g_cond_wait (&secret_context.cond, &secret_context.mutex);
+
+       g_mutex_unlock (&secret_context.mutex);
+       g_mutex_clear (&secret_context.mutex);
+       g_cond_clear (&secret_context.cond);
+       g_cancellable_cancel (secret_context.cancellable);
+       g_clear_object (&secret_context.cancellable);
 
-       gdk_threads_add_idle (show_login_dialog, &context);
+       if (priv->consumer_key != NULL &&
+           priv->consumer_secret != NULL &&
+           priv->token_key != NULL &&
+           priv->token_secret != NULL)
+               return TRUE;
 
-       while (!context.done)
-               g_cond_wait (&context.cond, &context.mutex);
+       /* Otherwise start with a clean slate */
+       g_clear_pointer (&priv->token_secret, g_free);
+       g_clear_pointer (&priv->token_key, g_free);
+       g_clear_pointer (&priv->consumer_secret, g_free);
+       g_clear_pointer (&priv->consumer_key, g_free);
 
-       g_mutex_unlock (&context.mutex);
-       g_mutex_clear (&context.mutex);
-       g_cond_clear (&context.cond);
+       /* Pop up a login dialog */
+       login_context.plugin = plugin;
+       login_context.error = error;
+       g_cond_init (&login_context.cond);
+       g_mutex_init (&login_context.mutex);
+       g_mutex_lock (&login_context.mutex);
+
+       gdk_threads_add_idle (show_login_dialog, &login_context);
+
+       while (!login_context.done)
+               g_cond_wait (&login_context.cond, &login_context.mutex);
+
+       g_mutex_unlock (&login_context.mutex);
+       g_mutex_clear (&login_context.mutex);
+       g_cond_clear (&login_context.cond);
+
+       if (login_context.remember) {
+               secret_password_store (&schema,
+                                      NULL,
+                                      SCHEMA_NAME,
+                                      priv->consumer_key,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      "key", CONSUMER_KEY,
+                                      NULL);
+
+               secret_password_store (&schema,
+                                      NULL,
+                                      SCHEMA_NAME,
+                                      priv->consumer_secret,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      "key", CONSUMER_SECRET,
+                                      NULL);
+
+               secret_password_store (&schema,
+                                      NULL,
+                                      SCHEMA_NAME,
+                                      priv->token_key,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      "key", TOKEN_KEY,
+                                      NULL);
+
+               secret_password_store (&schema,
+                                      NULL,
+                                      SCHEMA_NAME,
+                                      priv->token_secret,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      "key", TOKEN_SECRET,
+                                      NULL);
+       }
 
-       return context.success;
+       return login_context.success;
 }
 
 gboolean


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