[gnome-software/wip/william/cherry-pick-4: 3/23] Add utility module for Ubuntu One
- From: William Hua <williamhua src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/william/cherry-pick-4: 3/23] Add utility module for Ubuntu One
- Date: Fri, 3 Jun 2016 07:00:46 +0000 (UTC)
commit ed1a3f3bb7d72088c1c27265adcaeaf84913ec4d
Author: William Hua <william hua canonical com>
Date: Thu Jun 2 12:14:56 2016 -0400
Add utility module for Ubuntu One
Authored by Robert Ancell <robert ancell canonical com>, William Hua
<william hua canonical com> and Iain Lane <iain orangesquash org uk>.
configure.ac | 1 +
src/plugins/gs-ubuntuone.c | 410 ++++++++++++++++++++++++++++++++++++++++++++
src/plugins/gs-ubuntuone.h | 49 ++++++
3 files changed, 460 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3f89d83..b4cf971 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,6 +68,7 @@ PKG_CHECK_MODULES(SQLITE, sqlite3)
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(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/gs-ubuntuone.c b/src/plugins/gs-ubuntuone.c
new file mode 100644
index 0000000..3c7b582
--- /dev/null
+++ b/src/plugins/gs-ubuntuone.c
@@ -0,0 +1,410 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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.
+ */
+
+#include <config.h>
+
+#include <libsecret/secret.h>
+
+#include <gs-plugin.h>
+
+#include "gs-ubuntuone.h"
+#include "gs-ubuntuone-dialog.h"
+
+#define SCHEMA_NAME "com.ubuntu.UbuntuOne.GnomeSoftware"
+#define MACAROON "macaroon"
+#define CONSUMER_KEY "consumer-key"
+#define CONSUMER_SECRET "consumer-secret"
+#define TOKEN_KEY "token-key"
+#define TOKEN_SECRET "token-secret"
+
+static SecretSchema schema = {
+ SCHEMA_NAME,
+ SECRET_SCHEMA_NONE,
+ { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
+};
+
+typedef struct
+{
+ GError **error;
+
+ GCond cond;
+ GMutex mutex;
+
+ gboolean get_macaroon;
+
+ gboolean done;
+ gboolean success;
+ gboolean remember;
+
+ GVariant *macaroon;
+ gchar *consumer_key;
+ gchar *consumer_secret;
+ gchar *token_key;
+ gchar *token_secret;
+} LoginContext;
+
+static gboolean
+show_login_dialog (gpointer user_data)
+{
+ LoginContext *context = user_data;
+ GtkWidget *dialog;
+
+ dialog = gs_ubuntuone_dialog_new (context->get_macaroon);
+
+ switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ if (context->get_macaroon) {
+ g_set_error (context->error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Unable to obtain snapd macaroon");
+ } else {
+ g_set_error (context->error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Unable to sign into Ubuntu One");
+ }
+
+ context->success = FALSE;
+ break;
+
+ case GTK_RESPONSE_OK:
+ context->remember = gs_ubuntuone_dialog_get_do_remember (GS_UBUNTUONE_DIALOG (dialog));
+ context->macaroon = gs_ubuntuone_dialog_get_macaroon (GS_UBUNTUONE_DIALOG (dialog));
+ context->consumer_key = g_strdup (gs_ubuntuone_dialog_get_consumer_key (GS_UBUNTUONE_DIALOG
(dialog)));
+ context->consumer_secret = g_strdup (gs_ubuntuone_dialog_get_consumer_secret
(GS_UBUNTUONE_DIALOG (dialog)));
+ context->token_key = g_strdup (gs_ubuntuone_dialog_get_token_key (GS_UBUNTUONE_DIALOG
(dialog)));
+ context->token_secret = g_strdup (gs_ubuntuone_dialog_get_token_secret (GS_UBUNTUONE_DIALOG
(dialog)));
+ context->success = TRUE;
+
+ if (context->macaroon != NULL)
+ g_variant_ref (context->macaroon);
+
+ break;
+ }
+
+ gtk_widget_destroy (dialog);
+
+ g_mutex_lock (&context->mutex);
+ context->done = TRUE;
+ g_cond_signal (&context->cond);
+ g_mutex_unlock (&context->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+GVariant *
+gs_ubuntuone_get_macaroon (gboolean use_cache,
+ gboolean show_dialog,
+ GError **error)
+{
+ LoginContext login_context = { 0 };
+ g_autofree gchar *password = NULL;
+ g_autofree gchar *printed = NULL;
+ GVariant *macaroon = NULL;
+ GError *error_local = NULL;
+
+ if (use_cache) {
+ password = secret_password_lookup_sync (&schema,
+ NULL,
+ &error_local,
+ "key", MACAROON,
+ NULL);
+
+ if (password) {
+ macaroon = g_variant_parse (G_VARIANT_TYPE ("(sas)"),
+ password,
+ NULL,
+ NULL,
+ &error_local);
+
+ if (macaroon)
+ return macaroon;
+
+ g_warning ("could not parse macaroon: %s", error_local->message);
+ g_clear_error (&error_local);
+ } else if (error_local != NULL) {
+ g_warning ("could not lookup cached macaroon: %s", error_local->message);
+ g_clear_error (&error_local);
+ }
+ }
+
+ if (show_dialog) {
+ /* Pop up a login dialog */
+ login_context.error = error;
+ login_context.get_macaroon = TRUE;
+ 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.macaroon != NULL && login_context.remember) {
+ printed = g_variant_print (login_context.macaroon, FALSE);
+
+ if (!secret_password_store_sync (&schema,
+ NULL,
+ SCHEMA_NAME,
+ printed,
+ NULL,
+ &error_local,
+ "key", MACAROON,
+ NULL)) {
+ g_warning ("could not store macaroon: %s", error_local->message);
+ g_clear_error (&error_local);
+ }
+ }
+
+ return login_context.macaroon;
+ }
+
+ return NULL;
+}
+
+void
+gs_ubuntuone_clear_macaroon (void)
+{
+ secret_password_clear_sync (&schema, NULL, NULL, "key", MACAROON, NULL);
+}
+
+typedef struct
+{
+ GCancellable *cancellable;
+ GCond cond;
+ GMutex mutex;
+
+ gint waiting;
+
+ gchar *consumer_key;
+ gchar *consumer_secret;
+ gchar *token_key;
+ gchar *token_secret;
+} SecretContext;
+
+static void
+lookup_consumer_key (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SecretContext *context = user_data;
+
+ context->consumer_key = secret_password_lookup_finish (result, NULL);
+
+ g_mutex_lock (&context->mutex);
+
+ context->waiting--;
+
+ 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->consumer_secret = secret_password_lookup_finish (result, NULL);
+
+ g_mutex_lock (&context->mutex);
+
+ context->waiting--;
+
+ 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->token_key = secret_password_lookup_finish (result, NULL);
+
+ g_mutex_lock (&context->mutex);
+
+ context->waiting--;
+
+ 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->token_secret = secret_password_lookup_finish (result, NULL);
+
+ g_mutex_lock (&context->mutex);
+
+ context->waiting--;
+
+ g_cond_signal (&context->cond);
+ g_mutex_unlock (&context->mutex);
+}
+
+gboolean
+gs_ubuntuone_get_credentials (gchar **consumer_key, gchar **consumer_secret, gchar **token_key, gchar
**token_secret)
+{
+ SecretContext secret_context = { 0 };
+
+ /* Use credentials from libsecret if available */
+ 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);
+
+ if (secret_context.consumer_key != NULL &&
+ secret_context.consumer_secret != NULL &&
+ secret_context.token_key != NULL &&
+ secret_context.token_secret != NULL) {
+ *consumer_key = secret_context.consumer_key;
+ *consumer_secret = secret_context.consumer_secret;
+ *token_key = secret_context.token_key;
+ *token_secret = secret_context.token_secret;
+ return TRUE;
+ }
+
+ g_free (secret_context.token_secret);
+ g_free (secret_context.token_key);
+ g_free (secret_context.consumer_secret);
+ g_free (secret_context.consumer_key);
+ return FALSE;
+}
+
+gboolean
+gs_ubuntuone_sign_in (gchar **consumer_key, gchar **consumer_secret, gchar **token_key, gchar
**token_secret, GError **error)
+{
+ LoginContext login_context = { 0 };
+
+ /* Pop up a login dialog */
+ login_context.error = error;
+ login_context.get_macaroon = FALSE;
+ 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,
+ login_context.consumer_key,
+ NULL,
+ NULL,
+ NULL,
+ "key", CONSUMER_KEY,
+ NULL);
+
+ secret_password_store (&schema,
+ NULL,
+ SCHEMA_NAME,
+ login_context.consumer_secret,
+ NULL,
+ NULL,
+ NULL,
+ "key", CONSUMER_SECRET,
+ NULL);
+
+ secret_password_store (&schema,
+ NULL,
+ SCHEMA_NAME,
+ login_context.token_key,
+ NULL,
+ NULL,
+ NULL,
+ "key", TOKEN_KEY,
+ NULL);
+
+ secret_password_store (&schema,
+ NULL,
+ SCHEMA_NAME,
+ login_context.token_secret,
+ NULL,
+ NULL,
+ NULL,
+ "key", TOKEN_SECRET,
+ NULL);
+ }
+
+ *consumer_key = login_context.consumer_key;
+ *consumer_secret = login_context.consumer_secret;
+ *token_key = login_context.token_key;
+ *token_secret = login_context.token_secret;
+ return login_context.success;
+}
diff --git a/src/plugins/gs-ubuntuone.h b/src/plugins/gs-ubuntuone.h
new file mode 100644
index 0000000..4e9fde8
--- /dev/null
+++ b/src/plugins/gs-ubuntuone.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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.
+ */
+
+#ifndef __GS_UBUNTUONE_H
+#define __GS_UBUNTUONE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+GVariant *gs_ubuntuone_get_macaroon (gboolean use_cache,
+ gboolean show_dialog,
+ GError **error);
+
+void gs_ubuntuone_clear_macaroon (void);
+
+gboolean gs_ubuntuone_get_credentials (gchar **consumer_key,
+ gchar **consumer_secret,
+ gchar **token_key,
+ gchar **token_secret);
+
+gboolean gs_ubuntuone_sign_in (gchar **consumer_key,
+ gchar **consumer_secret,
+ gchar **token_key,
+ gchar **token_secret,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GS_UBUNTUONE_H */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]