[gnome-software] auth: Use gnome-online-accounts to handle the authentication
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] auth: Use gnome-online-accounts to handle the authentication
- Date: Thu, 13 Dec 2018 21:39:23 +0000 (UTC)
commit e1cce7348411c6790044d2c9cd96b8696ca5c126
Author: Andrea Azzarone <azzaronea gmail com>
Date: Mon Jun 4 14:51:47 2018 -0500
auth: Use gnome-online-accounts to handle the authentication
.gitlab-ci.yml | 1 +
contrib/gnome-software.spec.in | 2 +-
data/org.gnome.software.gschema.xml | 7 +
lib/gs-auth.c | 793 ++++++++++++------------------------
lib/gs-auth.h | 96 +----
lib/gs-plugin-job.c | 2 +-
lib/gs-plugin-loader.c | 15 +-
lib/gs-plugin-loader.h | 2 +-
lib/gs-plugin-types.h | 14 -
lib/gs-plugin-vfuncs.h | 64 ---
lib/gs-plugin.c | 36 +-
lib/gs-plugin.h | 2 +-
lib/gs-self-test.c | 49 ---
lib/meson.build | 6 +-
meson.build | 2 +-
plugins/dummy/gs-plugin-dummy.c | 103 +----
plugins/dummy/gs-self-test.c | 83 ----
plugins/dummy/meson.build | 2 +-
plugins/meson.build | 1 +
plugins/snap/gs-plugin-snap.c | 187 +++------
src/gs-auth-dialog.c | 559 +++++++++++++++----------
src/gs-auth-dialog.h | 8 +-
src/gs-auth-dialog.ui | 383 ++++++-----------
src/gs-page.c | 8 +-
src/gs-page.h | 2 +-
src/gs-shell.c | 170 +++-----
src/meson.build | 4 +-
27 files changed, 889 insertions(+), 1712 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0d99b81b..90093205 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,6 +11,7 @@ before_script:
# Some deps may not be sync'd
- dnf -y install rpm-ostree-devel
- dnf -y install libstemmer-devel
+ - dnf -y install gnome-online-accounts-devel
build-gnome-software:
stage: build
diff --git a/contrib/gnome-software.spec.in b/contrib/gnome-software.spec.in
index 0dec552d..aba9e487 100644
--- a/contrib/gnome-software.spec.in
+++ b/contrib/gnome-software.spec.in
@@ -34,11 +34,11 @@ BuildRequires: gtk3-devel >= %{gtk3_version}
BuildRequires: gtk-doc
BuildRequires: json-glib-devel >= %{json_glib_version}
BuildRequires: libappstream-glib-devel >= %{appstream_glib_version}
+BuildRequires: gnome-online-accounts-devel
BuildRequires: libsoup-devel
BuildRequires: meson
BuildRequires: PackageKit-glib-devel >= %{packagekit_version}
BuildRequires: polkit-devel
-BuildRequires: libsecret-devel
BuildRequires: flatpak-devel >= %{flatpak_version}
BuildRequires: ostree-devel
BuildRequires: rpm-ostree-devel
diff --git a/data/org.gnome.software.gschema.xml b/data/org.gnome.software.gschema.xml
index fab37c9e..97780e0d 100644
--- a/data/org.gnome.software.gschema.xml
+++ b/data/org.gnome.software.gschema.xml
@@ -139,5 +139,12 @@
<default>true</default>
<summary>Enable GNOME Shell extensions repository</summary>
</key>
+ <child name="auth" schema="org.gnome.software.auth"/>
+ </schema>
+ <schema id="org.gnome.software.auth" gettext-domain="gnome-software">
+ <key name="account-id" type="s">
+ <default>''</default>
+ <summary>A string storing the gnome-online-account id used to login</summary>
+ </key>
</schema>
</schemalist>
diff --git a/lib/gs-auth.c b/lib/gs-auth.c
index 098efd13..ecd60e50 100644
--- a/lib/gs-auth.c
+++ b/lib/gs-auth.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2018 Canonical Ltd
*
* Licensed under the GNU General Public License Version 2
*
@@ -32,612 +33,307 @@
#include "config.h"
-#include <libsecret/secret.h>
-
#include "gs-auth.h"
#include "gs-plugin.h"
struct _GsAuth
{
- GObject parent_instance;
-
- GsAuthFlags flags;
- gchar *provider_id;
- gchar *provider_name;
- gchar *provider_logo;
- gchar *provider_uri;
- gchar *provider_schema;
- gchar *username;
- gchar *password;
- gchar *pin;
- GHashTable *metadata; /* utf8: utf8 */
+ GObject parent_instance;
+
+ gchar *header_none;
+ gchar *header_single;
+ gchar *header_multiple;
+
+ gchar *auth_id;
+ gchar *provider_name;
+ gchar *provider_type;
+
+ GoaClient *goa_client;
+ GoaObject *goa_object;
+
+ GSettings *settings;
+};
+
+static void gs_auth_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GsAuth, gs_auth, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, gs_auth_initable_iface_init))
+
+enum {
+ SIGNAL_CHANGED,
+ SIGNAL_LAST
};
enum {
PROP_0,
- PROP_USERNAME,
- PROP_PASSWORD,
- PROP_PIN,
- PROP_FLAGS,
+ PROP_AUTH_ID,
+ PROP_PROVIDER_TYPE,
+ PROP_GOA_OBJECT,
PROP_LAST
};
-G_DEFINE_TYPE (GsAuth, gs_auth, G_TYPE_OBJECT)
+static guint signals [SIGNAL_LAST] = { 0 };
-/**
- * gs_auth_get_provider_id:
- * @auth: a #GsAuth
- *
- * Gets the authentication service ID.
- *
- * Returns: the string to use for searching, e.g. "UbuntuOne"
- */
-const gchar *
-gs_auth_get_provider_id (GsAuth *auth)
-{
- g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->provider_id;
-}
/**
- * gs_auth_get_provider_name:
+ * gs_auth_get_header:
* @auth: a #GsAuth
+ * @n: the number of accounts
*
- * Gets the authentication service name.
+ * Gets the header to be used in the authentication dialog in case there are @n
+ * available accounts.
*
- * Returns: the string to show in the UI
+ * Returns: (transfer none) : a string
*/
const gchar *
-gs_auth_get_provider_name (GsAuth *auth)
+gs_auth_get_header (GsAuth *auth, guint n)
{
g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->provider_name;
+
+ if (n == 0)
+ return auth->header_none;
+ else if (n == 1)
+ return auth->header_single;
+ else
+ return auth->header_multiple;
}
/**
- * gs_auth_set_provider_name:
+ * gs_auth_set_header:
* @auth: a #GsAuth
- * @provider_name: a service name, e.g. "GNOME Online Accounts"
+ * @header_none: the header to be used if no account is present
+ * @header_single: the header to be used if one account is present
+ * @header_multiple: the header to be used if two or more accounts are present
*
- * Sets the name to be used for the authentication dialog.
+ * Sets the headers to be used for the authentication dialog.
*/
void
-gs_auth_set_provider_name (GsAuth *auth, const gchar *provider_name)
+gs_auth_set_header (GsAuth *auth,
+ const gchar *header_none,
+ const gchar *header_single,
+ const gchar *header_multiple)
{
g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->provider_name);
- auth->provider_name = g_strdup (provider_name);
+ g_return_if_fail (header_none != NULL);
+ g_return_if_fail (header_single != NULL);
+ g_return_if_fail (header_multiple != NULL);
+
+ g_free (auth->header_none);
+ auth->header_none = g_strdup (header_none);
+
+ g_free (auth->header_single);
+ auth->header_single = g_strdup (header_single);
+
+ g_free (auth->header_multiple);
+ auth->header_multiple = g_strdup (header_multiple);
}
/**
- * gs_auth_get_provider_logo:
+ * gs_auth_get_auth_id:
* @auth: a #GsAuth
*
- * Gets the authentication service image.
+ * Gets the authentication service ID.
*
- * Returns: the filename of an image, or %NULL
+ * Returns: (transfer none): a string
*/
const gchar *
-gs_auth_get_provider_logo (GsAuth *auth)
+gs_auth_get_auth_id (GsAuth *auth)
{
g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->provider_logo;
-}
-
-/**
- * gs_auth_set_provider_logo:
- * @auth: a #GsAuth
- * @provider_logo: an image, e.g. "/usr/share/icons/gnome-online.png"
- *
- * Sets the image to be used for the authentication dialog.
- */
-void
-gs_auth_set_provider_logo (GsAuth *auth, const gchar *provider_logo)
-{
- g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->provider_logo);
- auth->provider_logo = g_strdup (provider_logo);
+ return auth->auth_id;
}
/**
- * gs_auth_get_provider_uri:
+ * gs_auth_get_provider_name:
* @auth: a #GsAuth
*
- * Gets the authentication service website.
+ * Gets the authentication service name.
*
- * Returns: the URI, or %NULL
+ * Returns: (transfer none): a string
*/
const gchar *
-gs_auth_get_provider_uri (GsAuth *auth)
+gs_auth_get_provider_name (GsAuth *auth)
{
g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->provider_uri;
+ return auth->provider_name;
}
/**
- * gs_auth_set_provider_uri:
+ * gs_auth_set_provider_name:
* @auth: a #GsAuth
- * @provider_uri: a URI, e.g. "http://www.gnome.org/sso"
+ * @provider_name: a service name, e.g. "Snap Store"
*
- * Sets the website to be used for the authentication dialog.
+ * Sets the name to be used for the authentication dialog.
*/
void
-gs_auth_set_provider_uri (GsAuth *auth, const gchar *provider_uri)
+gs_auth_set_provider_name (GsAuth *auth, const gchar *provider_name)
{
g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->provider_uri);
- auth->provider_uri = g_strdup (provider_uri);
+ g_return_if_fail (provider_name != NULL);
+
+ g_free (auth->provider_name);
+ auth->provider_name = g_strdup (provider_name);
}
/**
- * gs_auth_get_provider_schema:
+ * gs_auth_get_provider_type:
* @auth: a #GsAuth
*
- * Gets the authentication schema ID.
+ * Gets the GoaProvider type to be used for the authentication dialog.
*
- * Returns: the URI, or %NULL
+ * Returns: (transfer none): a string
*/
const gchar *
-gs_auth_get_provider_schema (GsAuth *auth)
+gs_auth_get_provider_type (GsAuth *auth)
{
g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->provider_schema;
+ return auth->provider_type;
}
/**
- * gs_auth_set_provider_schema:
+ * gs_auth_peek_goa_object:
* @auth: a #GsAuth
- * @provider_schema: a URI, e.g. "com.distro.provider"
*
- * Sets the schema ID to be used for saving the state to disk.
- */
-void
-gs_auth_set_provider_schema (GsAuth *auth, const gchar *provider_schema)
-{
- g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->provider_schema);
- auth->provider_schema = g_strdup (provider_schema);
-}
-
-/**
- * gs_auth_get_username:
- * @auth: a #GsAuth
- *
- * Gets the auth username.
+ * Gets the logged #GoaObject if any.
*
- * Returns: the username to be used for the authentication
+ * Returns: (transfer none) (nullable): a #GoaObject, or %NULL
*/
-const gchar *
-gs_auth_get_username (GsAuth *auth)
+GoaObject *
+gs_auth_peek_goa_object (GsAuth *auth)
{
g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->username;
+ return auth->goa_object;
}
-/**
- * gs_auth_set_username:
- * @auth: a #GsAuth
- * @username: a username, e.g. "hughsie"
- *
- * Sets the username to be used for the authentication.
- */
-void
-gs_auth_set_username (GsAuth *auth, const gchar *username)
+static gboolean
+gs_auth_goa_account_equal (GoaAccount *acc1, GoaAccount *acc2)
{
- g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->username);
- auth->username = g_strdup (username);
-}
+ if (acc1 == acc2)
+ return TRUE;
-/**
- * gs_auth_get_password:
- * @auth: a #GsAuth
- *
- * Gets the password to be used for the authentication.
- *
- * Returns: the string, or %NULL
- **/
-const gchar *
-gs_auth_get_password (GsAuth *auth)
-{
- g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->password;
-}
+ if (acc1 == NULL || acc2 == NULL)
+ return FALSE;
-/**
- * gs_auth_set_password:
- * @auth: a #GsAuth
- * @password: password string, e.g. "p@ssw0rd"
- *
- * Sets the password to be used for the authentication.
- */
-void
-gs_auth_set_password (GsAuth *auth, const gchar *password)
-{
- g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->password);
- auth->password = g_strdup (password);
+ return !g_strcmp0 (goa_account_get_id (acc1),
+ goa_account_get_id (acc2));
}
-/**
- * gs_auth_get_flags:
- * @auth: a #GsAuth
- *
- * Gets any flags set on the authentication, for example if we should remember
- * credentials.
- *
- * Returns: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- */
-GsAuthFlags
-gs_auth_get_flags (GsAuth *auth)
+static gboolean
+gs_auth_goa_object_equal (GoaObject *obj1, GoaObject *obj2)
{
- g_return_val_if_fail (GS_IS_AUTH (auth), 0);
- return auth->flags;
-}
+ if (obj1 == obj2)
+ return TRUE;
-/**
- * gs_auth_set_flags:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Gets any flags set on the authentication.
- */
-void
-gs_auth_set_flags (GsAuth *auth, GsAuthFlags flags)
-{
- g_return_if_fail (GS_IS_AUTH (auth));
- auth->flags = flags;
-}
+ if (obj1 == NULL || obj2 == NULL)
+ return FALSE;
-/**
- * gs_auth_add_flags:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Adds flags to an existing authentication without replacing the other flags.
- */
-void
-gs_auth_add_flags (GsAuth *auth, GsAuthFlags flags)
-{
- g_return_if_fail (GS_IS_AUTH (auth));
- auth->flags |= flags;
+ return gs_auth_goa_account_equal(goa_object_peek_account (obj1),
+ goa_object_peek_account (obj2));
}
-/**
- * gs_auth_has_flag:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Finds out if the authentication has a flag.
- *
- * Returns: %TRUE if set
- */
-gboolean
-gs_auth_has_flag (GsAuth *auth, GsAuthFlags flags)
+static void
+gs_auth_account_changed_cb (GoaClient *client,
+ GoaObject *goa_object,
+ GsAuth *auth)
{
- g_return_val_if_fail (GS_IS_AUTH (auth), FALSE);
- return (auth->flags & flags) > 0;
-}
+ if (!gs_auth_goa_object_equal (auth->goa_object, goa_object))
+ return;
-/**
- * gs_auth_get_pin:
- * @auth: a #GsAuth
- *
- * Gets the PIN code.
- *
- * Returns: the 2 factor authentication PIN, or %NULL
- **/
-const gchar *
-gs_auth_get_pin (GsAuth *auth)
-{
- g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- return auth->pin;
+ g_signal_emit (auth, signals[SIGNAL_CHANGED], 0);
}
-/**
- * gs_auth_set_pin:
- * @auth: a #GsAuth
- * @pin: the PIN code, e.g. "12345"
- *
- * Sets the 2 factor authentication PIN, which can be left unset.
- */
-void
-gs_auth_set_pin (GsAuth *auth, const gchar *pin)
+static void
+gs_auth_account_removed_cb (GoaClient *client,
+ GoaObject *goa_object,
+ GsAuth *auth)
{
- g_return_if_fail (GS_IS_AUTH (auth));
- g_free (auth->pin);
- auth->pin = g_strdup (pin);
-}
+ if (!gs_auth_goa_object_equal (auth->goa_object, goa_object))
+ return;
-/**
- * gs_auth_get_metadata_item:
- * @auth: a #GsAuth
- * @key: a string
- *
- * Gets some metadata from a authentication object.
- * It is left for the the plugin to use this method as required, but a
- * typical use would be to retrieve some secure auth token.
- *
- * Returns: A string value, or %NULL for not found
- */
-const gchar *
-gs_auth_get_metadata_item (GsAuth *auth, const gchar *key)
-{
- g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
- g_return_val_if_fail (key != NULL, NULL);
- return g_hash_table_lookup (auth->metadata, key);
+ gs_auth_set_goa_object (auth, NULL);
}
/**
- * gs_auth_add_metadata:
+ * gs_auth_set_goa_object:
* @auth: a #GsAuth
- * @key: a string
- * @value: a string
+ * @goa_object: (nullable) a #GoaObject
*
- * Adds metadata to the authentication object.
- * It is left for the the plugin to use this method as required, but a
- * typical use would be to store some secure auth token.
+ * Set the #GoaObject used to login in.
*/
void
-gs_auth_add_metadata (GsAuth *auth, const gchar *key, const gchar *value)
+gs_auth_set_goa_object (GsAuth *auth,
+ GoaObject *goa_object)
{
g_return_if_fail (GS_IS_AUTH (auth));
- g_hash_table_insert (auth->metadata, g_strdup (key), g_strdup (value));
-}
-
-static gboolean
-_g_error_is_set (GError **error)
-{
- if (error == NULL)
- return FALSE;
- return *error != NULL;
-}
-
-/**
- * gs_auth_store_load:
- * @auth: a #GsAuth
- * @flags: some #GsAuthStoreFlags, e.g. %GS_AUTH_STORE_FLAG_USERNAME
- * @cancellable: a #GCancellable or %NULL
- * @error: a #GError or %NULL
- *
- * Loads authentication tokens from disk in a secure way.
- * By default only the username and password are loaded, but they are not
- * overwritten if already set.
- *
- * If additional tokens are required to be loaded you must first tell the
- * GsAuth instance what metadata to load. This can be done using:
- * `gs_auth_add_metadata("additional-secret-key-name",NULL)`
- *
- * This function is expected to be called from gs_plugin_setup().
- *
- * Returns: %TRUE if the tokens were loaded correctly.
- */
-gboolean
-gs_auth_store_load (GsAuth *auth, GsAuthStoreFlags flags,
- GCancellable *cancellable, GError **error)
-{
- SecretSchema schema = {
- auth->provider_schema,
- SECRET_SCHEMA_NONE,
- { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
- };
-
- /* no schema */
- if (auth->provider_schema == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "No provider schema set for %s",
- auth->provider_id);
- return FALSE;
- }
- /* username */
- if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0 && auth->username == NULL) {
- auth->username = secret_password_lookup_sync (&schema,
- cancellable,
- error,
- "key", "username",
- NULL);
- if (_g_error_is_set (error))
- return FALSE;
- }
-
- /* password */
- if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0 && auth->password == NULL) {
- auth->password = secret_password_lookup_sync (&schema,
- cancellable,
- error,
- "key", "password",
- NULL);
- if (_g_error_is_set (error))
- return FALSE;
- }
+ if (gs_auth_goa_object_equal (auth->goa_object, goa_object))
+ return;
- /* metadata */
- if (flags & GS_AUTH_STORE_FLAG_METADATA) {
- g_autoptr(GList) keys = NULL;
- keys = g_hash_table_get_keys (auth->metadata);
- for (GList *l = keys; l != NULL; l = l->next) {
- g_autofree gchar *tmp = NULL;
- const gchar *key = l->data;
- const gchar *value = g_hash_table_lookup (auth->metadata, key);
- if (value != NULL)
- continue;
- tmp = secret_password_lookup_sync (&schema,
- cancellable,
- error,
- "key", key,
- NULL);
- if (_g_error_is_set (error))
- return FALSE;
- if (tmp != NULL)
- gs_auth_add_metadata (auth, key, tmp);
- }
- }
+ g_clear_object (&auth->goa_object);
+ if (goa_object)
+ auth->goa_object = g_object_ref (goa_object);
- /* success */
- return TRUE;
+ g_object_notify (G_OBJECT (auth), "goa-object");
+ g_signal_emit (auth, signals[SIGNAL_CHANGED], 0);
}
-/**
- * gs_auth_store_save:
- * @auth: a #GsAuth
- * @flags: some #GsAuthStoreFlags, e.g. %GS_AUTH_STORE_FLAG_USERNAME
- * @cancellable: a #GCancellable or %NULL
- * @error: a #GError or %NULL
- *
- * Saves the username, password and all added metadata to disk in a secure way.
- *
- * This function is expected to be called from gs_plugin_setup().
- *
- * Returns: %TRUE if the tokens were all saved correctly.
- */
-gboolean
-gs_auth_store_save (GsAuth *auth, GsAuthStoreFlags flags,
- GCancellable *cancellable, GError **error)
+static gboolean
+string_to_goa_object (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
{
- SecretSchema schema = {
- auth->provider_schema,
- SECRET_SCHEMA_NONE,
- { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
- };
-
- /* no schema */
- if (auth->provider_schema == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "No provider schema set for %s",
- auth->provider_id);
- return FALSE;
- }
+ GsAuth *auth = GS_AUTH (user_data);
+ GoaObject *goa_object;
+ const gchar *account_id;
- /* username */
- if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0 && auth->username != NULL) {
- if (!secret_password_store_sync (&schema,
- NULL, /* collection */
- auth->provider_schema,
- auth->username,
- cancellable, error,
- "key", "username", NULL))
- return FALSE;
- }
-
- /* password */
- if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0 && auth->password != NULL) {
- if (!secret_password_store_sync (&schema,
- NULL, /* collection */
- auth->provider_schema,
- auth->password,
- cancellable, error,
- "key", "password", NULL))
- return FALSE;
- }
+ account_id = g_variant_get_string (variant, NULL);
- /* metadata */
- if (flags & GS_AUTH_STORE_FLAG_METADATA) {
- g_autoptr(GList) keys = NULL;
- keys = g_hash_table_get_keys (auth->metadata);
- for (GList *l = keys; l != NULL; l = l->next) {
- const gchar *key = l->data;
- const gchar *value = g_hash_table_lookup (auth->metadata, key);
- if (value == NULL)
- continue;
- if (!secret_password_store_sync (&schema,
- NULL, /* collection */
- auth->provider_schema,
- value,
- cancellable, error,
- "key", key, NULL))
- return FALSE;
- }
- }
+ goa_object = goa_client_lookup_by_id (auth->goa_client, account_id);
+ if (!goa_object)
+ return TRUE;
- /* success */
+ g_value_take_object (value, goa_object);
return TRUE;
}
-gboolean
-gs_auth_store_clear (GsAuth *auth, GsAuthStoreFlags flags,
- GCancellable *cancellable, GError **error)
+static GVariant *
+goa_object_to_string (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
{
- SecretSchema schema = {
- auth->provider_schema,
- SECRET_SCHEMA_NONE,
- { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
- };
-
- /* no schema */
- if (auth->provider_schema == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "No provider schema set for %s",
- auth->provider_id);
- return FALSE;
- }
+ GObject *object = g_value_get_object (value);
- /* username */
- if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0) {
- if (!secret_password_clear_sync (&schema,
- cancellable, error,
- "key", "username", NULL))
- return FALSE;
- }
+ GoaObject *goa_object = object != NULL ? GOA_OBJECT (object) : NULL;
+ GoaAccount *goa_account = goa_object != NULL ? goa_object_peek_account (goa_object) : NULL;
- g_free (auth->username);
- auth->username = NULL;
-
- /* password */
- if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0) {
- if (!secret_password_clear_sync (&schema,
- cancellable, error,
- "key", "password", NULL))
- return FALSE;
- }
-
- g_free (auth->password);
- auth->password = NULL;
-
- /* metadata */
- if (flags & GS_AUTH_STORE_FLAG_METADATA) {
- g_autoptr(GList) keys = NULL;
- keys = g_hash_table_get_keys (auth->metadata);
- for (GList *l = keys; l != NULL; l = l->next) {
- const gchar *key = l->data;
- if (!secret_password_clear_sync (&schema,
- cancellable, error,
- "key", key, NULL))
- return FALSE;
-
- }
- }
+ if (goa_account != NULL)
+ return g_variant_new_string (goa_account_get_id (goa_account));
+ else
+ return g_variant_new_string ("");
+}
- g_hash_table_remove_all (auth->metadata);
+/* GObject */
- /* success */
- return TRUE;
+static void
+gs_auth_init (GsAuth *auth)
+{
}
static void
gs_auth_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
+ GValue *value, GParamSpec *pspec)
{
GsAuth *auth = GS_AUTH (object);
switch (prop_id) {
- case PROP_USERNAME:
- g_value_set_string (value, auth->username);
- break;
- case PROP_PASSWORD:
- g_value_set_string (value, auth->password);
+ case PROP_AUTH_ID:
+ g_value_set_string (value, auth->auth_id);
break;
- case PROP_FLAGS:
- g_value_set_uint64 (value, auth->flags);
+ case PROP_PROVIDER_TYPE:
+ g_value_set_string (value, auth->provider_type);
break;
- case PROP_PIN:
- g_value_set_string (value, auth->pin);
+ case PROP_GOA_OBJECT:
+ g_value_set_object (value, auth->goa_object);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -647,22 +343,19 @@ gs_auth_get_property (GObject *object, guint prop_id,
static void
gs_auth_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
+ const GValue *value, GParamSpec *pspec)
{
GsAuth *auth = GS_AUTH (object);
switch (prop_id) {
- case PROP_USERNAME:
- gs_auth_set_username (auth, g_value_get_string (value));
+ case PROP_AUTH_ID:
+ auth->auth_id = g_value_dup_string (value);
break;
- case PROP_PASSWORD:
- gs_auth_set_password (auth, g_value_get_string (value));
+ case PROP_PROVIDER_TYPE:
+ auth->provider_type = g_value_dup_string (value);
break;
- case PROP_FLAGS:
- gs_auth_set_flags (auth, g_value_get_uint64 (value));
- break;
- case PROP_PIN:
- gs_auth_set_pin (auth, g_value_get_string (value));
+ case PROP_GOA_OBJECT:
+ gs_auth_set_goa_object (auth, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -675,15 +368,16 @@ gs_auth_finalize (GObject *object)
{
GsAuth *auth = GS_AUTH (object);
- g_free (auth->provider_id);
+ g_free (auth->header_none);
+ g_free (auth->header_single);
+ g_free (auth->header_multiple);
+ g_free (auth->auth_id);
g_free (auth->provider_name);
- g_free (auth->provider_logo);
- g_free (auth->provider_uri);
- g_free (auth->provider_schema);
- g_free (auth->username);
- g_free (auth->password);
- g_free (auth->pin);
- g_hash_table_unref (auth->metadata);
+
+ g_clear_object (&auth->goa_client);
+ g_clear_object (&auth->goa_object);
+
+ g_clear_object (&auth->settings);
G_OBJECT_CLASS (gs_auth_parent_class)->finalize (object);
}
@@ -693,64 +387,99 @@ gs_auth_class_init (GsAuthClass *klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
object_class->finalize = gs_auth_finalize;
object_class->get_property = gs_auth_get_property;
object_class->set_property = gs_auth_set_property;
- /**
- * GsAuth:username:
- */
- pspec = g_param_spec_string ("username", NULL, NULL,
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
- g_object_class_install_property (object_class, PROP_USERNAME, pspec);
-
- /**
- * GsAuth:password:
- */
- pspec = g_param_spec_string ("password", NULL, NULL,
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
- g_object_class_install_property (object_class, PROP_PASSWORD, pspec);
-
- /**
- * GsAuth:flags:
- */
- pspec = g_param_spec_uint64 ("flags", NULL, NULL,
- GS_AUTH_FLAG_NONE,
- GS_AUTH_FLAG_LAST,
- GS_AUTH_FLAG_NONE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
- g_object_class_install_property (object_class, PROP_FLAGS, pspec);
-
- /**
- * GsAuth:pin:
- */
- pspec = g_param_spec_string ("pin", NULL, NULL,
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
- g_object_class_install_property (object_class, PROP_PIN, pspec);
+ pspec = g_param_spec_string ("auth-id", NULL, NULL, NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_AUTH_ID, pspec);
+
+ pspec = g_param_spec_string ("provider-type", NULL, NULL, NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_PROVIDER_TYPE, pspec);
+
+ pspec = g_param_spec_object ("goa-object", NULL, NULL,
+ GOA_TYPE_OBJECT,
+ G_PARAM_READWRITE |
+ G_PARAM_EXPLICIT_NOTIFY);
+ g_object_class_install_property (object_class, PROP_GOA_OBJECT, pspec);
+
+ signals [SIGNAL_CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 0);
+}
+
+/* GInitable */
+
+static gboolean
+gs_auth_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsAuth *self;
+ g_autofree gchar *path = NULL;
+
+ g_return_val_if_fail (GS_IS_AUTH (initable), FALSE);
+
+ self = GS_AUTH (initable);
+
+ self->goa_client = goa_client_new_sync (NULL, error);
+ if (self->goa_client == NULL)
+ return FALSE;
+
+ g_signal_connect (self->goa_client, "account-changed",
+ G_CALLBACK (gs_auth_account_changed_cb), self);
+ g_signal_connect (self->goa_client, "account-removed",
+ G_CALLBACK (gs_auth_account_removed_cb), self);
+
+ path = g_strdup_printf ("/org/gnome/software/auth/%s/", self->auth_id);
+ self->settings = g_settings_new_with_path ("org.gnome.software.auth", path);
+
+ g_settings_bind_with_mapping (self->settings, "account-id",
+ self, "goa-object",
+ G_SETTINGS_BIND_DEFAULT,
+ string_to_goa_object,
+ goa_object_to_string,
+ self, NULL);
+
+ return TRUE;
}
static void
-gs_auth_init (GsAuth *auth)
+gs_auth_initable_iface_init (GInitableIface *iface)
{
- auth->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
+ iface->init = gs_auth_initable_init;
}
/**
* gs_auth_new:
- * @provider_id: a provider ID used for mapping, e.g. "GnomeSSO"
+ * @auth_id: an identifier used for mapping, e.g. "snapd"
+ * @provider_type: the name of the GoaProvider466 to be used, e.g. "ubuntusso"
+ * @error: A #GError
*
- * Return value: a new #GsAuth object.
+ * Return value: (transfer full) (nullable): a new #GsAuth object.
**/
GsAuth *
-gs_auth_new (const gchar *provider_id)
+gs_auth_new (const gchar *auth_id,
+ const gchar *provider_type,
+ GError **error)
{
GsAuth *auth;
- auth = g_object_new (GS_TYPE_AUTH, NULL);
- auth->provider_id = g_strdup (provider_id);
+
+ g_return_val_if_fail (auth_id != NULL, NULL);
+ g_return_val_if_fail (provider_type != NULL, NULL);
+
+ auth = g_initable_new (GS_TYPE_AUTH, NULL, error,
+ "auth-id", auth_id,
+ "provider-type", provider_type,
+ NULL);
+
return GS_AUTH (auth);
}
diff --git a/lib/gs-auth.h b/lib/gs-auth.h
index 55df1a7d..c2018f67 100644
--- a/lib/gs-auth.h
+++ b/lib/gs-auth.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2018 Canonical Ltd
*
* Licensed under the GNU General Public License Version 2
*
@@ -24,6 +25,8 @@
#include <glib-object.h>
#include <gio/gio.h>
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+#include <goa/goa.h>
G_BEGIN_DECLS
@@ -31,88 +34,23 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GsAuth, gs_auth, GS, AUTH, GObject)
-/**
- * GsAuthFlags:
- * @GS_AUTH_FLAG_NONE: No special flags set
- * @GS_AUTH_FLAG_VALID: Authorisation is valid
- * @GS_AUTH_FLAG_REMEMBER: Remember this authentication if possible
- *
- * The flags for the auth.
- **/
-typedef enum {
- GS_AUTH_FLAG_NONE = 0,
- GS_AUTH_FLAG_VALID = 1 << 0,
- GS_AUTH_FLAG_REMEMBER = 1 << 1,
- /*< private >*/
- GS_AUTH_FLAG_LAST
-} GsAuthFlags;
-
-/**
- * GsAuthStoreFlags:
- * @GS_AUTH_STORE_FLAG_NONE: No special flags set
- * @GS_AUTH_STORE_FLAG_USERNAME: Load or save the username
- * @GS_AUTH_STORE_FLAG_PASSWORD: Load or save the password
- * @GS_AUTH_STORE_FLAG_METADATA: Load or save any metadata
- *
- * The flags used when loading or saving the authentication to disk.
- **/
-typedef enum {
- GS_AUTH_STORE_FLAG_NONE = 0,
- GS_AUTH_STORE_FLAG_USERNAME = 1 << 0,
- GS_AUTH_STORE_FLAG_PASSWORD = 1 << 1,
- GS_AUTH_STORE_FLAG_METADATA = 1 << 2,
- /*< private >*/
- GS_AUTH_STORE_FLAG_LAST
-} GsAuthStoreFlags;
-
-GsAuth *gs_auth_new (const gchar *provider_id);
-const gchar *gs_auth_get_provider_id (GsAuth *auth);
+GsAuth *gs_auth_new (const gchar *auth_id,
+ const gchar *provider_type,
+ GError **error);
+const gchar *gs_auth_get_header (GsAuth *auth,
+ guint n);
+void gs_auth_set_header (GsAuth *auth,
+ const gchar *header_none,
+ const gchar *header_single,
+ const gchar *header_multiple);
+const gchar *gs_auth_get_auth_id (GsAuth *auth);
const gchar *gs_auth_get_provider_name (GsAuth *auth);
void gs_auth_set_provider_name (GsAuth *auth,
const gchar *provider_name);
-const gchar *gs_auth_get_provider_logo (GsAuth *auth);
-void gs_auth_set_provider_logo (GsAuth *auth,
- const gchar *provider_logo);
-const gchar *gs_auth_get_provider_uri (GsAuth *auth);
-void gs_auth_set_provider_uri (GsAuth *auth,
- const gchar *provider_uri);
-const gchar *gs_auth_get_provider_schema (GsAuth *auth);
-void gs_auth_set_provider_schema (GsAuth *auth,
- const gchar *provider_schema);
-const gchar *gs_auth_get_username (GsAuth *auth);
-void gs_auth_set_username (GsAuth *auth,
- const gchar *username);
-const gchar *gs_auth_get_password (GsAuth *auth);
-void gs_auth_set_password (GsAuth *auth,
- const gchar *password);
-const gchar *gs_auth_get_pin (GsAuth *auth);
-void gs_auth_set_pin (GsAuth *auth,
- const gchar *pin);
-GsAuthFlags gs_auth_get_flags (GsAuth *auth);
-void gs_auth_set_flags (GsAuth *auth,
- GsAuthFlags flags);
-void gs_auth_add_flags (GsAuth *auth,
- GsAuthFlags flags);
-gboolean gs_auth_has_flag (GsAuth *auth,
- GsAuthFlags flags);
-const gchar *gs_auth_get_metadata_item (GsAuth *auth,
- const gchar *key);
-void gs_auth_add_metadata (GsAuth *auth,
- const gchar *key,
- const gchar *value);
-gboolean gs_auth_store_load (GsAuth *auth,
- GsAuthStoreFlags flags,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_auth_store_save (GsAuth *auth,
- GsAuthStoreFlags flags,
- GCancellable *cancellable,
- GError **error);
-gboolean gs_auth_store_clear (GsAuth *auth,
- GsAuthStoreFlags flags,
- GCancellable *cancellable,
- GError **error);
-
+const gchar *gs_auth_get_provider_type (GsAuth *auth);
+GoaObject *gs_auth_peek_goa_object (GsAuth *auth);
+void gs_auth_set_goa_object (GsAuth *auth,
+ GoaObject *goa_object);
G_END_DECLS
#endif /* __GS_AUTH_H */
diff --git a/lib/gs-plugin-job.c b/lib/gs-plugin-job.c
index 4254194c..e1d8bc79 100644
--- a/lib/gs-plugin-job.c
+++ b/lib/gs-plugin-job.c
@@ -131,7 +131,7 @@ gs_plugin_job_to_string (GsPluginJob *self)
}
if (self->auth != NULL) {
g_string_append_printf (str, " with auth=%s",
- gs_auth_get_provider_id (self->auth));
+ gs_auth_get_auth_id (self->auth));
}
if (self->file != NULL) {
g_autofree gchar *path = g_file_get_path (self->file);
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 5f469262..d298d4f6 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -720,17 +720,6 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
cancellable, &error_local);
}
break;
- case GS_PLUGIN_ACTION_AUTH_LOGIN:
- case GS_PLUGIN_ACTION_AUTH_LOGOUT:
- case GS_PLUGIN_ACTION_AUTH_REGISTER:
- case GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD:
- {
- GsPluginAuthFunc plugin_func = func;
- ret = plugin_func (plugin,
- gs_plugin_job_get_auth (helper->plugin_job),
- cancellable, &error_local);
- }
- break;
default:
g_critical ("no handler for %s", helper->function_name);
break;
@@ -2140,7 +2129,7 @@ gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader)
GsAuth *
gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
- const gchar *provider_id)
+ const gchar *auth_id)
{
GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
guint i;
@@ -2148,7 +2137,7 @@ gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
/* match on ID */
for (i = 0; i < priv->auth_array->len; i++) {
GsAuth *auth = g_ptr_array_index (priv->auth_array, i);
- if (g_strcmp0 (gs_auth_get_provider_id (auth), provider_id) == 0)
+ if (g_strcmp0 (gs_auth_get_auth_id (auth), auth_id) == 0)
return auth;
}
return NULL;
diff --git a/lib/gs-plugin-loader.h b/lib/gs-plugin-loader.h
index bb013826..16ad468a 100644
--- a/lib/gs-plugin-loader.h
+++ b/lib/gs-plugin-loader.h
@@ -80,7 +80,7 @@ gboolean gs_plugin_loader_get_enabled (GsPluginLoader *plugin_loader,
void gs_plugin_loader_add_location (GsPluginLoader *plugin_loader,
const gchar *location);
GsAuth *gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
- const gchar *provider_id);
+ const gchar *auth_id);
GPtrArray *gs_plugin_loader_get_auths (GsPluginLoader *plugin_loader);
guint gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader);
void gs_plugin_loader_set_scale (GsPluginLoader *plugin_loader,
diff --git a/lib/gs-plugin-types.h b/lib/gs-plugin-types.h
index f3c67e8e..aae56646 100644
--- a/lib/gs-plugin-types.h
+++ b/lib/gs-plugin-types.h
@@ -73,9 +73,6 @@ typedef guint64 GsPluginFlags;
* @GS_PLUGIN_ERROR_NO_SPACE: No disk space to allow action
* @GS_PLUGIN_ERROR_AUTH_REQUIRED: Authentication was required
* @GS_PLUGIN_ERROR_AUTH_INVALID: Provided authentication was invalid
- * @GS_PLUGIN_ERROR_PIN_REQUIRED: PIN required for authentication
- * @GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED: User account has been suspended
- * @GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED: User account has been deactivated
* @GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED: The plugins installed are incompatible
* @GS_PLUGIN_ERROR_DOWNLOAD_FAILED: The download action failed
* @GS_PLUGIN_ERROR_WRITE_FAILED: The save-to-disk failed
@@ -98,9 +95,6 @@ typedef enum {
GS_PLUGIN_ERROR_NO_SPACE,
GS_PLUGIN_ERROR_AUTH_REQUIRED,
GS_PLUGIN_ERROR_AUTH_INVALID,
- GS_PLUGIN_ERROR_PIN_REQUIRED,
- GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED,
- GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED,
GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED,
GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
GS_PLUGIN_ERROR_WRITE_FAILED,
@@ -242,10 +236,6 @@ typedef enum {
* @GS_PLUGIN_ACTION_REFINE: Refine the application
* @GS_PLUGIN_ACTION_REFRESH: Refresh all the sources
* @GS_PLUGIN_ACTION_FILE_TO_APP: Convert the file to an application
- * @GS_PLUGIN_ACTION_AUTH_LOGIN: Authentication login action
- * @GS_PLUGIN_ACTION_AUTH_LOGOUT: Authentication logout action
- * @GS_PLUGIN_ACTION_AUTH_REGISTER: Authentication register action
- * @GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD: Authentication lost password action
* @GS_PLUGIN_ACTION_URL_TO_APP: Convert the file to an application
* @GS_PLUGIN_ACTION_GET_RECENT: Get the apps recently released
* @GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL: Get the list of historical updates
@@ -291,10 +281,6 @@ typedef enum {
GS_PLUGIN_ACTION_REFINE,
GS_PLUGIN_ACTION_REFRESH,
GS_PLUGIN_ACTION_FILE_TO_APP,
- GS_PLUGIN_ACTION_AUTH_LOGIN,
- GS_PLUGIN_ACTION_AUTH_LOGOUT,
- GS_PLUGIN_ACTION_AUTH_REGISTER,
- GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD,
GS_PLUGIN_ACTION_URL_TO_APP,
GS_PLUGIN_ACTION_GET_RECENT,
GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL,
diff --git a/lib/gs-plugin-vfuncs.h b/lib/gs-plugin-vfuncs.h
index 011acdf4..a30fe7a5 100644
--- a/lib/gs-plugin-vfuncs.h
+++ b/lib/gs-plugin-vfuncs.h
@@ -977,70 +977,6 @@ gboolean gs_plugin_update (GsPlugin *plugin,
GCancellable *cancellable,
GError **error);
-/**
- * gs_plugin_auth_login:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs a login using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean gs_plugin_auth_login (GsPlugin *plugin,
- GsAuth *auth,
- GCancellable *cancellable,
- GError **error);
-
-/**
- * gs_plugin_auth_logout:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs a logout using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean gs_plugin_auth_logout (GsPlugin *plugin,
- GsAuth *auth,
- GCancellable *cancellable,
- GError **error);
-
-/**
- * gs_plugin_auth_lost_password:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs the lost password action using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean gs_plugin_auth_lost_password (GsPlugin *plugin,
- GsAuth *auth,
- GCancellable *cancellable,
- GError **error);
-
-/**
- * gs_plugin_auth_register:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs the registration action using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean gs_plugin_auth_register (GsPlugin *plugin,
- GsAuth *auth,
- GCancellable *cancellable,
- GError **error);
-
G_END_DECLS
#endif /* __GS_PLUGIN_VFUNCS_H */
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index 4af3bc8a..28374bfc 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -645,7 +645,7 @@ gs_plugin_add_auth (GsPlugin *plugin, GsAuth *auth)
/**
* gs_plugin_get_auth_by_id:
* @plugin: a #GsPlugin
- * @provider_id: an ID, e.g. "dummy-sso"
+ * @auth_id: an ID, e.g. "dummy-sso"
*
* Gets a specific authentication object.
*
@@ -654,7 +654,7 @@ gs_plugin_add_auth (GsPlugin *plugin, GsAuth *auth)
* Since: 3.22
**/
GsAuth *
-gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *provider_id)
+gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *auth_id)
{
GsPluginPrivate *priv = gs_plugin_get_instance_private (plugin);
guint i;
@@ -662,7 +662,7 @@ gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *provider_id)
/* match on ID */
for (i = 0; i < priv->auth_array->len; i++) {
GsAuth *auth = g_ptr_array_index (priv->auth_array, i);
- if (g_strcmp0 (gs_auth_get_provider_id (auth), provider_id) == 0)
+ if (g_strcmp0 (gs_auth_get_auth_id (auth), auth_id) == 0)
return auth;
}
return NULL;
@@ -1544,12 +1544,6 @@ gs_plugin_error_to_string (GsPluginError error)
return "auth-required";
if (error == GS_PLUGIN_ERROR_AUTH_INVALID)
return "auth-invalid";
- if (error == GS_PLUGIN_ERROR_PIN_REQUIRED)
- return "pin-required";
- if (error == GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED)
- return "account-suspended";
- if (error == GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED)
- return "account-deactivated";
if (error == GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED)
return "plugin-depsolve-failed";
if (error == GS_PLUGIN_ERROR_DOWNLOAD_FAILED)
@@ -1650,14 +1644,6 @@ gs_plugin_action_to_function_name (GsPluginAction action)
return "gs_plugin_add_search_files";
if (action == GS_PLUGIN_ACTION_SEARCH_PROVIDES)
return "gs_plugin_add_search_what_provides";
- if (action == GS_PLUGIN_ACTION_AUTH_LOGIN)
- return "gs_plugin_auth_login";
- if (action == GS_PLUGIN_ACTION_AUTH_LOGOUT)
- return "gs_plugin_auth_logout";
- if (action == GS_PLUGIN_ACTION_AUTH_REGISTER)
- return "gs_plugin_auth_register";
- if (action == GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD)
- return "gs_plugin_auth_lost_password";
if (action == GS_PLUGIN_ACTION_GET_CATEGORY_APPS)
return "gs_plugin_add_category_apps";
if (action == GS_PLUGIN_ACTION_GET_CATEGORIES)
@@ -1756,14 +1742,6 @@ gs_plugin_action_to_string (GsPluginAction action)
return "file-to-app";
if (action == GS_PLUGIN_ACTION_URL_TO_APP)
return "url-to-app";
- if (action == GS_PLUGIN_ACTION_AUTH_LOGIN)
- return "auth-login";
- if (action == GS_PLUGIN_ACTION_AUTH_LOGOUT)
- return "auth-logout";
- if (action == GS_PLUGIN_ACTION_AUTH_REGISTER)
- return "auth-register";
- if (action == GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD)
- return "auth-lost-password";
if (action == GS_PLUGIN_ACTION_GET_RECENT)
return "get-recent";
if (action == GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL)
@@ -1860,14 +1838,6 @@ gs_plugin_action_from_string (const gchar *action)
return GS_PLUGIN_ACTION_FILE_TO_APP;
if (g_strcmp0 (action, "url-to-app") == 0)
return GS_PLUGIN_ACTION_URL_TO_APP;
- if (g_strcmp0 (action, "auth-login") == 0)
- return GS_PLUGIN_ACTION_AUTH_LOGIN;
- if (g_strcmp0 (action, "auth-logout") == 0)
- return GS_PLUGIN_ACTION_AUTH_LOGOUT;
- if (g_strcmp0 (action, "auth-register") == 0)
- return GS_PLUGIN_ACTION_AUTH_REGISTER;
- if (g_strcmp0 (action, "auth-lost-password") == 0)
- return GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD;
if (g_strcmp0 (action, "get-recent") == 0)
return GS_PLUGIN_ACTION_GET_RECENT;
if (g_strcmp0 (action, "get-updates-historical") == 0)
diff --git a/lib/gs-plugin.h b/lib/gs-plugin.h
index 692fa85e..ac0ffaa7 100644
--- a/lib/gs-plugin.h
+++ b/lib/gs-plugin.h
@@ -89,7 +89,7 @@ void gs_plugin_set_soup_session (GsPlugin *plugin,
void gs_plugin_add_auth (GsPlugin *plugin,
GsAuth *auth);
GsAuth *gs_plugin_get_auth_by_id (GsPlugin *plugin,
- const gchar *provider_id);
+ const gchar *auth_id);
void gs_plugin_add_rule (GsPlugin *plugin,
GsPluginRule rule,
const gchar *name);
diff --git a/lib/gs-self-test.c b/lib/gs-self-test.c
index b5ba3736..9fd4a45c 100644
--- a/lib/gs-self-test.c
+++ b/lib/gs-self-test.c
@@ -707,54 +707,6 @@ gs_app_func (void)
gs_app_set_state_recover (app);
}
-static void
-gs_auth_secret_func (void)
-{
- gboolean ret;
- g_autoptr(GDBusConnection) conn = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsAuth) auth1 = NULL;
- g_autoptr(GsAuth) auth2 = NULL;
-
- /* we not have an active session bus */
- conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
- if (conn == NULL) {
- g_prefix_error (&error, "no session bus available: ");
- g_test_skip (error->message);
- return;
- }
-
- /* save secrets to disk */
- auth1 = gs_auth_new ("self-test");
- gs_auth_set_provider_schema (auth1, "org.gnome.Software.Dummy");
- gs_auth_set_username (auth1, "hughsie");
- gs_auth_set_password (auth1, "foobarbaz");
- gs_auth_add_metadata (auth1, "day", "monday");
- ret = gs_auth_store_save (auth1,
- GS_AUTH_STORE_FLAG_USERNAME |
- GS_AUTH_STORE_FLAG_PASSWORD |
- GS_AUTH_STORE_FLAG_METADATA,
- NULL, &error);
- g_assert_no_error (error);
- g_assert (ret);
-
- /* load secrets from disk */
- auth2 = gs_auth_new ("self-test");
- gs_auth_add_metadata (auth2, "day", NULL);
- gs_auth_add_metadata (auth2, "notgoingtoexist", NULL);
- gs_auth_set_provider_schema (auth2, "org.gnome.Software.Dummy");
- ret = gs_auth_store_load (auth2,
- GS_AUTH_STORE_FLAG_USERNAME |
- GS_AUTH_STORE_FLAG_PASSWORD |
- GS_AUTH_STORE_FLAG_METADATA,
- NULL, &error);
- g_assert_no_error (error);
- g_assert (ret);
- g_assert_cmpstr (gs_auth_get_username (auth2), ==, "hughsie");
- g_assert_cmpstr (gs_auth_get_password (auth2), ==, "foobarbaz");
- g_assert_cmpstr (gs_auth_get_metadata_item (auth2, "day"), ==, "monday");
-}
-
static void
gs_app_list_func (void)
{
@@ -831,7 +783,6 @@ main (int argc, char **argv)
g_test_add_func ("/gnome-software/lib/app{list-related}", gs_app_list_related_func);
g_test_add_func ("/gnome-software/lib/plugin", gs_plugin_func);
g_test_add_func ("/gnome-software/lib/plugin{download-rewrite}", gs_plugin_download_rewrite_func);
- g_test_add_func ("/gnome-software/lib/auth{secret}", gs_auth_secret_func);
return g_test_run ();
}
diff --git a/lib/meson.build b/lib/meson.build
index 7b11e72c..766d379c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -57,10 +57,10 @@ librarydeps = [
appstream_glib,
gio_unix,
gmodule,
+ goa,
gtk,
json_glib,
libm,
- libsecret,
libsoup,
valgrind,
]
@@ -108,10 +108,10 @@ executable(
appstream_glib,
gio_unix,
gmodule,
+ goa,
gtk,
json_glib,
libm,
- libsecret,
libsoup,
valgrind,
],
@@ -138,10 +138,10 @@ if get_option('tests')
appstream_glib,
gio_unix,
gmodule,
+ goa,
gtk,
json_glib,
libm,
- libsecret,
libsoup
],
link_with : [
diff --git a/meson.build b/meson.build
index ef349e67..34877ece 100644
--- a/meson.build
+++ b/meson.build
@@ -101,10 +101,10 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.32.0')
libxmlb = dependency('xmlb', version : '>= 0.1.4', fallback : ['libxmlb', 'libxmlb_dep'])
gio_unix = dependency('gio-unix-2.0', version : '>= 2.56.0')
gmodule = dependency('gmodule-2.0')
+goa = dependency('goa-1.0')
gtk = dependency('gtk+-3.0', version : '>= 3.22.4')
json_glib = dependency('json-glib-1.0', version : '>= 1.2.0')
libm = cc.find_library('m', required: false)
-libsecret = dependency('libsecret-1')
libsoup = dependency('libsoup-2.4', version : '>= 2.52.0')
if get_option('valgrind')
diff --git a/plugins/dummy/gs-plugin-dummy.c b/plugins/dummy/gs-plugin-dummy.c
index cb6c6ce1..cf1769c9 100644
--- a/plugins/dummy/gs-plugin-dummy.c
+++ b/plugins/dummy/gs-plugin-dummy.c
@@ -69,14 +69,11 @@ gs_plugin_initialize (GsPlugin *plugin)
}
/* set up a dummy authentication provider */
- priv->auth = gs_auth_new (gs_plugin_get_name (plugin));
- gs_auth_set_provider_name (priv->auth, "GNOME SSO");
- gs_auth_set_provider_logo (priv->auth, "/usr/share/pixmaps/gnome-about-logo.png");
- gs_auth_set_provider_uri (priv->auth, "http://www.gnome.org/sso");
- gs_plugin_add_auth (plugin, priv->auth);
-
- /* lets assume we read this from disk somewhere */
- gs_auth_set_username (priv->auth, "dummy");
+ priv->auth = gs_auth_new (gs_plugin_get_name (plugin), "google", NULL);
+ if (priv->auth != NULL) {
+ gs_auth_set_provider_name (priv->auth, "GNOME SSO");
+ gs_plugin_add_auth (plugin, priv->auth);
+ }
/* add source */
priv->cached_origin = gs_app_new (gs_plugin_get_name (plugin));
@@ -980,93 +977,3 @@ gs_plugin_review_remove (GsPlugin *plugin,
g_debug ("Removing dummy self-review");
return TRUE;
}
-
-gboolean
-gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- /* not us */
- if (g_strcmp0 (gs_auth_get_provider_id (auth),
- gs_auth_get_provider_id (priv->auth)) != 0)
- return TRUE;
-
- /* already logged in */
- if (priv->has_auth)
- return TRUE;
-
- /* check username and password */
- if (g_strcmp0 (gs_auth_get_username (priv->auth), "dummy") != 0 ||
- g_strcmp0 (gs_auth_get_password (priv->auth), "dummy") != 0) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_INVALID,
- "The password was not correct.");
- return FALSE;
- }
-
- priv->has_auth = TRUE;
- gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
- g_debug ("dummy now authenticated");
- return TRUE;
-}
-
-gboolean
-gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- /* not us */
- if (g_strcmp0 (gs_auth_get_provider_id (auth),
- gs_auth_get_provider_id (priv->auth)) != 0)
- return TRUE;
-
- /* not logged in */
- if (!priv->has_auth)
- return TRUE;
-
- priv->has_auth = FALSE;
- gs_auth_set_flags (priv->auth, 0);
- g_debug ("dummy now not authenticated");
- return TRUE;
-}
-
-gboolean
-gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- /* not us */
- if (g_strcmp0 (gs_auth_get_provider_id (auth),
- gs_auth_get_provider_id (priv->auth)) != 0)
- return TRUE;
-
- /* return with data */
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_INVALID,
- "do online using @http://www.gnome.org/lost-password/");
- return FALSE;
-}
-
-gboolean
-gs_plugin_auth_register (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- /* not us */
- if (g_strcmp0 (gs_auth_get_provider_id (auth),
- gs_auth_get_provider_id (priv->auth)) != 0)
- return TRUE;
-
- /* return with data */
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_INVALID,
- "do online using @http://www.gnome.org/register/");
- return FALSE;
-}
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
index 87a35d0f..1c7cc694 100644
--- a/plugins/dummy/gs-self-test.c
+++ b/plugins/dummy/gs-self-test.c
@@ -566,86 +566,6 @@ gs_plugins_dummy_plugin_cache_func (GsPluginLoader *plugin_loader)
g_assert (app1 == app2);
}
-static void
-gs_plugins_dummy_authentication_func (GsPluginLoader *plugin_loader)
-{
- GsAuth *auth;
- gboolean ret;
- g_autoptr(GError) error = NULL;
- g_autoptr(GsApp) app = NULL;
- g_autoptr(GsAppList) list = NULL;
- g_autoptr(AsReview) review = NULL;
- g_autoptr(AsReview) review2 = NULL;
- g_autoptr(GsPluginJob) plugin_job = NULL;
-
- /* check initial state */
- auth = gs_plugin_loader_get_auth_by_id (plugin_loader, "dummy");
- g_assert (GS_IS_AUTH (auth));
- g_assert_cmpint (gs_auth_get_flags (auth), ==, 0);
-
- /* do an action that returns a URL */
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_REGISTER,
- "auth", auth,
- NULL);
- list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
- g_assert (list == NULL);
- g_clear_error (&error);
- g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* do an action that requires a login */
- app = gs_app_new (NULL);
- review = as_review_new ();
- g_object_unref (plugin_job);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REVIEW_REMOVE,
- "app", app,
- "review", review,
- NULL);
- ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_REQUIRED);
- g_assert (!ret);
- g_clear_error (&error);
-
- /* pretend to auth with no credentials */
- g_object_unref (plugin_job);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
- "auth", auth,
- NULL);
- list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
- gs_test_flush_main_context ();
- g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
- g_assert (list == NULL);
- g_clear_error (&error);
- g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* auth again with correct credentials */
- gs_auth_set_username (auth, "dummy");
- gs_auth_set_password (auth, "dummy");
- g_object_unref (plugin_job);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
- "auth", auth,
- NULL);
- list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (list != NULL);
- g_assert (gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
- /* do the action that requires a login */
- review2 = as_review_new ();
- g_object_unref (plugin_job);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REVIEW_REMOVE,
- "app", app,
- "review", review2,
- NULL);
- ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
- gs_test_flush_main_context ();
- g_assert_no_error (error);
- g_assert (ret);
-}
-
static void
gs_plugins_dummy_wildcard_func (GsPluginLoader *plugin_loader)
{
@@ -937,9 +857,6 @@ main (int argc, char **argv)
g_test_add_data_func ("/gnome-software/plugins/dummy/wildcard",
plugin_loader,
(GTestDataFunc) gs_plugins_dummy_wildcard_func);
- g_test_add_data_func ("/gnome-software/plugins/dummy/authentication",
- plugin_loader,
- (GTestDataFunc) gs_plugins_dummy_authentication_func);
g_test_add_data_func ("/gnome-software/plugins/dummy/plugin-cache",
plugin_loader,
(GTestDataFunc) gs_plugins_dummy_plugin_cache_func);
diff --git a/plugins/dummy/meson.build b/plugins/dummy/meson.build
index 2359f295..1259c330 100644
--- a/plugins/dummy/meson.build
+++ b/plugins/dummy/meson.build
@@ -12,7 +12,7 @@ shared_module(
install : true,
install_dir: plugin_dir,
c_args : cargs,
- dependencies : [appstream_glib, gio_unix, gtk, libsoup]
+ dependencies : [appstream_glib, gio_unix, goa, gtk, libsoup]
)
if get_option('tests')
diff --git a/plugins/meson.build b/plugins/meson.build
index bd182141..f38fc048 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -2,6 +2,7 @@ plugin_dir = join_paths(get_option('libdir'), 'gs-plugins-' + gs_plugin_api_vers
plugin_libs = [
appstream_glib,
gio_unix,
+ goa,
gtk,
json_glib,
libsoup
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index 85b616a4..0ba51385 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2015-2016 Canonical Ltd
+ * Copyright (C) 2015-2018 Canonical Ltd
*
* Licensed under the GNU General Public License Version 2
*
@@ -54,6 +54,9 @@ get_client (GsPlugin *plugin, GError **error)
return g_steal_pointer (&client);
}
+static void
+load_auth (GsPlugin *plugin);
+
void
gs_plugin_initialize (GsPlugin *plugin)
{
@@ -72,10 +75,19 @@ gs_plugin_initialize (GsPlugin *plugin)
priv->store_snaps = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) g_object_unref);
- priv->auth = gs_auth_new ("snapd");
- gs_auth_set_provider_name (priv->auth, "Snap Store");
- gs_auth_set_provider_schema (priv->auth, "com.ubuntu.SnapStore.GnomeSoftware");
- gs_plugin_add_auth (plugin, priv->auth);
+ priv->auth = gs_auth_new ("snapd", "ubuntusso", &error);
+ if (priv->auth) {
+ gs_auth_set_provider_name (priv->auth, "Snap Store");
+ gs_auth_set_header (priv->auth, _("To continue, you need to use an Ubuntu One account."),
+ _("To continue, you need to use your Ubuntu One account."),
+ _("To continue, you need to use an Ubuntu One account."));
+ gs_plugin_add_auth (plugin, priv->auth);
+ g_signal_connect_object (priv->auth, "changed",
+ G_CALLBACK (load_auth),
+ plugin, G_CONNECT_SWAPPED);
+ } else {
+ g_warning ("Failed to instantiate the snapd authentication object: %s", error->message);
+ }
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories");
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_BETTER_THAN, "packagekit");
@@ -116,9 +128,6 @@ snapd_error_convert (GError **perror)
g_free (error->message);
error->message = g_strdup ("Requires authentication with @snapd");
break;
- case SNAPD_ERROR_TWO_FACTOR_REQUIRED:
- error->code = GS_PLUGIN_ERROR_PIN_REQUIRED;
- break;
case SNAPD_ERROR_AUTH_DATA_INVALID:
case SNAPD_ERROR_TWO_FACTOR_INVALID:
error->code = GS_PLUGIN_ERROR_AUTH_INVALID;
@@ -160,32 +169,53 @@ load_auth (GsPlugin *plugin)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
GsAuth *auth;
- const gchar *serialized_macaroon;
- g_autoptr(GVariant) macaroon_variant = NULL;
- const gchar *macaroon;
- g_auto(GStrv) discharges = NULL;
+ GoaObject *goa_object;
+ GoaPasswordBased *password_based;
+ g_autofree gchar *macaroon = NULL;
+ g_autofree gchar *discharges_str = NULL;
+ g_autoptr(GVariant) discharges_var = NULL;
+ g_autofree const gchar **discharges = NULL;
g_autoptr(SnapdAuthData) auth_data = NULL;
+ g_autoptr(GError) error = NULL;
auth = gs_plugin_get_auth_by_id (plugin, "snapd");
if (auth == NULL)
return;
- serialized_macaroon = gs_auth_get_metadata_item (auth, "macaroon");
- if (serialized_macaroon == NULL)
+ g_clear_object (&priv->auth_data);
+ goa_object = gs_auth_peek_goa_object (auth);
+ if (goa_object == NULL)
+ return;
+
+ password_based = goa_object_peek_password_based (goa_object);
+ g_return_if_fail (password_based != NULL);
+
+ goa_password_based_call_get_password_sync (password_based,
+ "macaroon",
+ &macaroon,
+ NULL, &error);
+ if (error != NULL) {
+ g_warning ("Failed to get macaroon: %s", error->message);
return;
+ }
- macaroon_variant = g_variant_parse (G_VARIANT_TYPE ("(sas)"),
- serialized_macaroon,
- NULL,
- NULL,
- NULL);
- if (macaroon_variant == NULL)
+ goa_password_based_call_get_password_sync (password_based,
+ "discharges",
+ &discharges_str,
+ NULL, &error);
+ if (error != NULL) {
+ g_warning ("Failed to get discharges %s", error->message);
return;
+ }
+
+ if (discharges_str)
+ discharges_var = g_variant_parse (G_VARIANT_TYPE ("as"),
+ discharges_str,
+ NULL, NULL, NULL);
+ if (discharges_var)
+ discharges = g_variant_get_strv (discharges_var, NULL);
- g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges);
- g_clear_object (&priv->auth_data);
priv->auth_data = snapd_auth_data_new (macaroon, discharges);
- gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
}
gboolean
@@ -208,15 +238,6 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
_("Snap Store"));
priv->system_confinement = snapd_system_information_get_confinement (system_information);
- /* load from disk */
- gs_auth_add_metadata (priv->auth, "macaroon", NULL);
- if (!gs_auth_store_load (priv->auth,
- GS_AUTH_STORE_FLAG_USERNAME |
- GS_AUTH_STORE_FLAG_METADATA,
- cancellable, error))
- return FALSE;
- load_auth (plugin);
-
/* success */
return TRUE;
}
@@ -1042,105 +1063,3 @@ gs_plugin_app_remove (GsPlugin *plugin,
gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
return TRUE;
}
-
-gboolean
-gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
- g_autoptr(SnapdClient) client = NULL;
- g_autoptr(SnapdUserInformation) user_information = NULL;
- g_autoptr(GVariant) macaroon_variant = NULL;
- g_autofree gchar *serialized_macaroon = NULL;
-
- if (auth != priv->auth)
- return TRUE;
-
- g_clear_object (&priv->auth_data);
-
- client = get_client (plugin, error);
- if (client == NULL)
- return FALSE;
-
- user_information = snapd_client_login2_sync (client, gs_auth_get_username (auth),
gs_auth_get_password (auth), gs_auth_get_pin (auth), NULL, error);
- if (user_information == NULL) {
- snapd_error_convert (error);
- return FALSE;
- }
-
- priv->auth_data = g_object_ref (snapd_user_information_get_auth_data (user_information));
-
- macaroon_variant = g_variant_new ("(s^as)",
- snapd_auth_data_get_macaroon (priv->auth_data),
- snapd_auth_data_get_discharges (priv->auth_data));
- serialized_macaroon = g_variant_print (macaroon_variant, FALSE);
- gs_auth_add_metadata (auth, "macaroon", serialized_macaroon);
-
- /* store */
- if (!gs_auth_store_save (auth,
- GS_AUTH_STORE_FLAG_USERNAME |
- GS_AUTH_STORE_FLAG_METADATA,
- cancellable, error))
- return FALSE;
-
- gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
-
- return TRUE;
-}
-
-gboolean
-gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- if (auth != priv->auth)
- return TRUE;
-
- /* clear */
- if (!gs_auth_store_clear (auth,
- GS_AUTH_STORE_FLAG_USERNAME |
- GS_AUTH_STORE_FLAG_METADATA,
- cancellable, error))
- return FALSE;
-
- g_clear_object (&priv->auth_data);
- gs_auth_set_flags (priv->auth, 0);
- return TRUE;
-}
-
-gboolean
-gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- if (auth != priv->auth)
- return TRUE;
-
- // FIXME: snapd might not be using Ubuntu One accounts
- // https://bugs.launchpad.net/bugs/1598667
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_INVALID,
- "do online using @https://login.ubuntu.com/+forgot_password");
- return FALSE;
-}
-
-gboolean
-gs_plugin_auth_register (GsPlugin *plugin, GsAuth *auth,
- GCancellable *cancellable, GError **error)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
-
- if (auth != priv->auth)
- return TRUE;
-
- // FIXME: snapd might not be using Ubuntu One accounts
- // https://bugs.launchpad.net/bugs/1598667
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_INVALID,
- "do online using @https://login.ubuntu.com/+login");
- return FALSE;
-}
diff --git a/src/gs-auth-dialog.c b/src/gs-auth-dialog.c
index 0b90fa81..6716b7c3 100644
--- a/src/gs-auth-dialog.c
+++ b/src/gs-auth-dialog.c
@@ -2,6 +2,7 @@
*
* Copyright (C) 2016 Richard Hughes <richard hughsie com>
* Copyright (C) 2017 Kalev Lember <klember redhat com>
+ * Copyright (C) 2018 Canonical Ltd
*
* Licensed under the GNU General Public License Version 2
*
@@ -23,272 +24,355 @@
#include "config.h"
#include <glib/gi18n.h>
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+#include <goa/goa.h>
#include "gs-auth-dialog.h"
#include "gs-common.h"
struct _GsAuthDialog
{
- GtkDialog parent_instance;
-
- GCancellable *cancellable;
- GsPluginLoader *plugin_loader;
- GsApp *app;
- GsAuth *auth;
- GtkWidget *box_dialog;
- GtkWidget *box_error;
- GtkWidget *button_cancel;
- GtkWidget *button_continue;
- GtkWidget *checkbutton_remember;
- GtkWidget *entry_password;
- GtkWidget *entry_pin;
- GtkWidget *entry_username;
- GtkWidget *image_vendor;
- GtkWidget *label_error;
- GtkWidget *label_title;
- GtkWidget *radiobutton_already;
- GtkWidget *radiobutton_lost_pwd;
- GtkWidget *radiobutton_register;
- GtkWidget *stack;
+ GtkDialog parent_instance;
+
+ GoaClient *goa_client;
+ GtkListStore *liststore_account;
+
+ GtkWidget *label_header;
+ GtkWidget *combobox_account;
+ GtkWidget *label_account;
+ GtkWidget *button_add_another;
+ GtkWidget *button_cancel;
+ GtkWidget *button_continue;
+
+ gboolean dispose_on_new_account;
+
+ GCancellable *cancellable;
+ GsPluginLoader *plugin_loader;
+ GsApp *app;
+ GsAuth *auth;
};
-G_DEFINE_TYPE (GsAuthDialog, gs_auth_dialog, GTK_TYPE_DIALOG)
+static void gs_auth_dialog_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GsAuthDialog, gs_auth_dialog, GTK_TYPE_DIALOG,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gs_auth_dialog_initable_iface_init))
+
+enum {
+ COLUMN_ID,
+ COLUMN_EMAIL,
+ COLUMN_ACCOUNT,
+ N_COLUMNS
+};
+
+static gboolean
+gs_auth_dialog_ignore_account (GsAuthDialog *self, GoaAccount *account)
+{
+ return g_strcmp0 (goa_account_get_provider_type (account),
+ gs_auth_get_provider_type (self->auth)) != 0;
+}
static void
-gs_auth_dialog_check_ui (GsAuthDialog *dialog)
+gs_auth_dialog_set_header (GsAuthDialog *self,
+ const gchar *text)
{
- g_autofree gchar *title = NULL;
- const gchar *tmp;
- const gchar *username = gtk_entry_get_text (GTK_ENTRY (dialog->entry_username));
- const gchar *password = gtk_entry_get_text (GTK_ENTRY (dialog->entry_password));
-
- /* set the header */
- tmp = gs_auth_get_provider_name (dialog->auth);
- if (tmp == NULL) {
- /* TRANSLATORS: this is when the service name is not known */
- title = g_strdup (_("To continue you need to sign in."));
- gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
- } else {
- /* TRANSLATORS: the %s is a service name, e.g. "Ubuntu One" */
- title = g_strdup_printf (_("To continue you need to sign in to %s."), tmp);
- gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
- }
+ g_autofree gchar *markup = NULL;
+ markup = g_strdup_printf ("<span size='larger' weight='bold'>%s</span>", text);
+ gtk_label_set_markup (GTK_LABEL (self->label_header), markup);
+}
- /* set the vendor image */
- tmp = gs_auth_get_provider_logo (dialog->auth);
- if (tmp == NULL) {
- gtk_widget_hide (dialog->image_vendor);
- } else {
- gtk_image_set_from_file (GTK_IMAGE (dialog->image_vendor), tmp);
- gtk_widget_show (dialog->image_vendor);
+static gint
+gs_auth_dialog_get_naccounts (GsAuthDialog *self)
+{
+ return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->liststore_account), NULL);
+}
+
+static gboolean
+gs_auth_dialog_get_nth_account_data (GsAuthDialog *self,
+ gint n,
+ ...)
+{
+ GtkTreeIter iter;
+ va_list var_args;
+
+ if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->liststore_account), &iter, NULL, n))
+ return FALSE;
+
+ va_start (var_args, n);
+ gtk_tree_model_get_valist (GTK_TREE_MODEL (self->liststore_account), &iter, var_args);
+ va_end (var_args);
+
+ return TRUE;
+}
+
+static gboolean
+gs_auth_dialog_get_account_iter (GsAuthDialog *self,
+ GoaAccount *account,
+ GtkTreeIter *iter)
+{
+ gboolean valid;
+
+ valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->liststore_account), iter, NULL, 0);
+
+ while (valid) {
+ g_autofree gchar *id;
+ gtk_tree_model_get (GTK_TREE_MODEL (self->liststore_account), iter, COLUMN_ID, &id, -1);
+ if (g_strcmp0 (id, goa_account_get_id (account)) == 0)
+ return TRUE;
+ else
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->liststore_account), iter);
}
- /* need username and password to continue for known account */
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_already))) {
- gtk_widget_set_sensitive (dialog->button_continue,
- username[0] != '\0' && password[0] != '\0');
- gtk_widget_set_sensitive (dialog->checkbutton_remember, TRUE);
+ return FALSE;
+}
+
+
+static void
+gs_auth_dialog_check_ui (GsAuthDialog *self,
+ gboolean select)
+{
+ gint naccounts = gs_auth_dialog_get_naccounts (self);
+
+ gs_auth_dialog_set_header (self, gs_auth_get_header (self->auth, naccounts));
+
+ if (naccounts == 0) {
+ gtk_widget_set_visible (self->combobox_account, FALSE);
+ gtk_widget_set_visible (self->label_account, FALSE);
+ gtk_widget_set_visible (self->button_add_another, FALSE);
+ gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Sign In / Register…"));
+ } else if (naccounts == 1) {
+ g_autofree gchar *email = NULL;
+
+ gtk_widget_set_visible (self->combobox_account, FALSE);
+ gtk_widget_set_visible (self->label_account, TRUE);
+ gtk_widget_set_visible (self->button_add_another, TRUE);
+ gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Continue"));
+ gs_auth_dialog_get_nth_account_data (self, 0, COLUMN_EMAIL, &email, -1);
+ gtk_label_set_text (GTK_LABEL (self->label_account), email);
} else {
- gtk_entry_set_text (GTK_ENTRY (dialog->entry_password), "");
- gtk_widget_set_sensitive (dialog->button_continue,
- username[0] != '\0');
- gtk_widget_set_sensitive (dialog->checkbutton_remember, FALSE);
+ gtk_widget_set_visible (self->combobox_account, TRUE);
+ gtk_widget_set_visible (self->label_account, FALSE);
+ gtk_widget_set_visible (self->button_add_another, TRUE);
+ gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Use"));
+
+ if (select)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox_account), naccounts - 1);
+ else if (gtk_combo_box_get_active (GTK_COMBO_BOX (self->combobox_account)) == -1)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox_account), 0);
}
}
static void
-gs_auth_dialog_cancel_button_cb (GtkWidget *widget, GsAuthDialog *dialog)
+gs_auth_dialog_add_account (GsAuthDialog *self,
+ GoaAccount *account,
+ gboolean select)
{
- gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+ GtkTreeIter iter;
+
+ if (gs_auth_dialog_ignore_account (self, account) ||
+ gs_auth_dialog_get_account_iter (self, account, &iter))
+ return;
+
+ gtk_list_store_append (self->liststore_account, &iter);
+ gtk_list_store_set (self->liststore_account, &iter,
+ COLUMN_ID, goa_account_get_id (account),
+ COLUMN_EMAIL, goa_account_get_presentation_identity (account),
+ COLUMN_ACCOUNT, account,
+ -1);
+
+ gs_auth_dialog_check_ui (self, select);
}
static void
-gs_auth_dialog_authenticate_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+gs_auth_dialog_remove_account (GsAuthDialog *self,
+ GoaAccount *account)
{
- GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
- GsAuthDialog *dialog = GS_AUTH_DIALOG (user_data);
- g_autoptr(GError) error = NULL;
+ GtkTreeIter iter;
- gtk_widget_set_sensitive (dialog->box_dialog, TRUE);
- gtk_widget_set_sensitive (dialog->button_continue, TRUE);
-
- gtk_widget_set_visible (dialog->box_error, FALSE);
-
- /* we failed */
- if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
- const gchar *url;
-
- if (g_error_matches (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_PIN_REQUIRED)) {
- gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "2fa");
- gtk_widget_grab_focus (dialog->entry_pin);
- return;
- }
-
- /* have we been given a link */
- url = gs_utils_get_error_value (error);
- if (url != NULL) {
- g_autoptr(GError) error_local = NULL;
- g_debug ("showing link in: %s", error->message);
- if (!gtk_show_uri_on_window (GTK_WINDOW (dialog),
- url,
- GDK_CURRENT_TIME,
- &error_local)) {
- g_warning ("failed to show URI %s: %s",
- url, error_local->message);
- }
- return;
- }
-
- g_warning ("failed to authenticate: %s", error->message);
- gtk_label_set_label (GTK_LABEL (dialog->label_error), error->message);
- gtk_widget_set_visible (dialog->box_error, TRUE);
+ if (gs_auth_dialog_ignore_account (self, account) ||
+ !gs_auth_dialog_get_account_iter (self, account, &iter))
return;
+
+
+ gtk_list_store_remove (self->liststore_account, &iter);
+ gs_auth_dialog_check_ui (self, FALSE);
+}
+
+static void
+gs_auth_dialog_setup_model (GsAuthDialog *self)
+{
+ g_autoptr(GList) accounts = goa_client_get_accounts (self->goa_client);
+
+ for (GList *l = accounts; l != NULL; l = l->next) {
+ gs_auth_dialog_add_account (self, goa_object_peek_account (l->data), FALSE);
+ g_object_unref (l->data);
}
+}
- /* we didn't get authenticated */
- if (!gs_auth_has_flag (dialog->auth, GS_AUTH_FLAG_VALID)) {
- return;
+static GVariant*
+gs_auth_dialog_build_dbus_parameters (const gchar *action,
+ const gchar *arg)
+{
+ GVariantBuilder builder;
+ GVariant *array[1], *params2[3];
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+
+ if (!action && !arg) {
+ g_variant_builder_add (&builder, "v", g_variant_new_string (""));
+ } else {
+ if (action)
+ g_variant_builder_add (&builder, "v", g_variant_new_string (action));
+
+ if (arg)
+ g_variant_builder_add (&builder, "v", g_variant_new_string (arg));
}
- /* success */
- gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ array[0] = g_variant_new ("v", g_variant_new ("(sav)", "online-accounts", &builder));
+
+ params2[0] = g_variant_new_string ("launch-panel");
+ params2[1] = g_variant_new_array (G_VARIANT_TYPE ("v"), array, 1);
+ params2[2] = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
+
+ return g_variant_new_tuple (params2, 3);
}
static void
-gs_auth_dialog_continue_cb (GtkWidget *widget, GsAuthDialog *dialog)
+gs_auth_dialog_spawn_goa_with_args (const gchar *action,
+ const gchar *arg)
{
- g_autoptr(GsPluginJob) plugin_job = NULL;
-
- gtk_widget_set_sensitive (dialog->box_dialog, FALSE);
- gtk_widget_set_sensitive (dialog->button_continue, FALSE);
-
- /* alternate actions */
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_lost_pwd))) {
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD,
- "auth", dialog->auth,
- NULL);
- } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_register))) {
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_REGISTER,
- "auth", dialog->auth,
- NULL);
- } else {
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
- "auth", dialog->auth,
- NULL);
+ g_autoptr(GDBusProxy) proxy = NULL;
+
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.gnome.ControlCenter",
+ "/org/gnome/ControlCenter",
+ "org.gtk.Actions",
+ NULL,
+ NULL);
+
+ if (!proxy)
+ {
+ g_warning ("Couldn't open Online Accounts panel");
+ return;
}
- gs_plugin_loader_job_process_async (dialog->plugin_loader, plugin_job,
- dialog->cancellable,
- gs_auth_dialog_authenticate_cb,
- dialog);
+
+ g_dbus_proxy_call_sync (proxy,
+ "Activate",
+ gs_auth_dialog_build_dbus_parameters (action, arg),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL);
}
static void
-gs_auth_dialog_setup (GsAuthDialog *dialog)
+gs_auth_dialog_ensure_crendentials_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
+ GsAuthDialog *self = (GsAuthDialog*) user_data;
+ GoaAccount *account = GOA_ACCOUNT (source_object);
+ g_autoptr(GError) error = NULL;
- /* update widgets with known values */
- if (gs_auth_get_username (dialog->auth) != NULL) {
- gtk_entry_set_text (GTK_ENTRY (dialog->entry_username),
- gs_auth_get_username (dialog->auth));
- }
- if (gs_auth_get_password (dialog->auth) != NULL) {
- gtk_entry_set_text (GTK_ENTRY (dialog->entry_password),
- gs_auth_get_password (dialog->auth));
- }
+ if (!goa_account_call_ensure_credentials_finish (account, NULL, res, &error)) {
+ gs_auth_dialog_spawn_goa_with_args (goa_account_get_id (account), NULL);
+ } else {
+ GoaObject *goa_object;
- /* refresh UI */
- gs_auth_dialog_check_ui (dialog);
+ goa_object = goa_client_lookup_by_id (self->goa_client,
+ goa_account_get_id (account));
+
+ gs_auth_set_goa_object (self->auth, goa_object);
+ gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK);
+ }
}
static void
-gs_auth_dialog_notify_username_cb (GtkEntry *entry,
- GParamSpec *pspec,
- GsAuthDialog *dialog)
+gs_auth_dialog_response_if_valid (GsAuthDialog *self,
+ GoaAccount *account)
{
- gs_auth_set_username (dialog->auth, gtk_entry_get_text (entry));
- gs_auth_dialog_check_ui (dialog);
+ goa_account_call_ensure_credentials (account,
+ self->cancellable,
+ gs_auth_dialog_ensure_crendentials_cb,
+ self);
}
static void
-gs_auth_dialog_notify_password_cb (GtkEntry *entry,
- GParamSpec *pspec,
- GsAuthDialog *dialog)
+gs_auth_dialog_account_added_cb (GoaClient *client,
+ GoaObject *object,
+ GsAuthDialog *self)
{
- gs_auth_set_password (dialog->auth, gtk_entry_get_text (entry));
- gs_auth_dialog_check_ui (dialog);
+ GoaAccount *account = goa_object_peek_account (object);
+
+ if (gs_auth_dialog_ignore_account (self, account))
+ return;
+
+ if (!self->dispose_on_new_account)
+ gs_auth_dialog_add_account (self, account, FALSE);
+ else
+ gs_auth_dialog_response_if_valid (self, account);
}
static void
-gs_auth_dialog_notify_pin_cb (GtkEntry *entry,
- GParamSpec *pspec,
- GsAuthDialog *dialog)
+gs_auth_dialog_account_removed_cb (GoaClient *client,
+ GoaObject *object,
+ GsAuthDialog *self)
{
- gs_auth_set_pin (dialog->auth, gtk_entry_get_text (entry));
- gs_auth_dialog_check_ui (dialog);
+ GoaAccount *account = goa_object_peek_account (object);
+ gs_auth_dialog_remove_account (self, account);
}
static void
-gs_auth_dialog_toggled_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+gs_auth_dialog_button_add_another_cb (GtkButton *button,
+ GsAuthDialog *self)
{
- gs_auth_dialog_check_ui (dialog);
+ gs_auth_dialog_spawn_goa_with_args ("add", gs_auth_get_provider_type (self->auth));
+ self->dispose_on_new_account = TRUE;
}
static void
-gs_auth_dialog_remember_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+gs_auth_dialog_button_cancel_cb (GtkButton *button,
+ GsAuthDialog *self)
{
- if (gtk_toggle_button_get_active (togglebutton))
- gs_auth_add_flags (dialog->auth, GS_AUTH_FLAG_REMEMBER);
- gs_auth_dialog_check_ui (dialog);
+ gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CANCEL);
}
static void
-gs_auth_dialog_dispose (GObject *object)
+gs_auth_dialog_button_continue_cb (GtkButton *button,
+ GsAuthDialog *self)
{
- GsAuthDialog *dialog = GS_AUTH_DIALOG (object);
+ GoaAccount *account = NULL;
+ gint naccounts = gs_auth_dialog_get_naccounts (self);
- g_clear_object (&dialog->plugin_loader);
- g_clear_object (&dialog->app);
- g_clear_object (&dialog->auth);
+ if (naccounts == 1) {
+ gs_auth_dialog_get_nth_account_data (self, 0, COLUMN_ACCOUNT, &account, -1);
+ } else {
+ gint active = gtk_combo_box_get_active (GTK_COMBO_BOX (self->combobox_account));
+ gs_auth_dialog_get_nth_account_data (self, active, COLUMN_ACCOUNT, &account, -1);
+ }
- g_cancellable_cancel (dialog->cancellable);
- g_clear_object (&dialog->cancellable);
+ if (account == NULL)
+ gs_auth_dialog_button_add_another_cb (GTK_BUTTON (self->button_add_another), self);
+ else
+ gs_auth_dialog_response_if_valid (self, account);
- G_OBJECT_CLASS (gs_auth_dialog_parent_class)->dispose (object);
+ g_clear_object (&account);
}
+/* GObject */
+
static void
-gs_auth_dialog_init (GsAuthDialog *dialog)
+gs_auth_dialog_dispose (GObject *object)
{
- gtk_widget_init_template (GTK_WIDGET (dialog));
-
- dialog->cancellable = g_cancellable_new ();
-
- g_signal_connect (dialog->entry_username, "notify::text",
- G_CALLBACK (gs_auth_dialog_notify_username_cb), dialog);
- g_signal_connect (dialog->entry_password, "notify::text",
- G_CALLBACK (gs_auth_dialog_notify_password_cb), dialog);
- g_signal_connect (dialog->entry_password, "activate",
- G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
- g_signal_connect (dialog->entry_pin, "notify::text",
- G_CALLBACK (gs_auth_dialog_notify_pin_cb), dialog);
- g_signal_connect (dialog->entry_pin, "activate",
- G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
- g_signal_connect (dialog->checkbutton_remember, "toggled",
- G_CALLBACK (gs_auth_dialog_remember_cb), dialog);
- g_signal_connect (dialog->radiobutton_already, "toggled",
- G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
- g_signal_connect (dialog->radiobutton_register, "toggled",
- G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
- g_signal_connect (dialog->radiobutton_lost_pwd, "toggled",
- G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
- g_signal_connect (dialog->button_cancel, "clicked",
- G_CALLBACK (gs_auth_dialog_cancel_button_cb), dialog);
- g_signal_connect (dialog->button_continue, "clicked",
- G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
+ GsAuthDialog *self = GS_AUTH_DIALOG (object);
+
+ g_clear_object (&self->goa_client);
+
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+
+ G_OBJECT_CLASS (gs_auth_dialog_parent_class)->dispose (object);
}
static void
@@ -301,34 +385,72 @@ gs_auth_dialog_class_init (GsAuthDialogClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-auth-dialog.ui");
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, box_dialog);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, box_error);
+ gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_header);
+ gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, combobox_account);
+ gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_account);
+ gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_add_another);
gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_cancel);
gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_continue);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, checkbutton_remember);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_password);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_pin);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_username);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, image_vendor);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_error);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_title);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_already);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_lost_pwd);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_register);
- gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, stack);
+ gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, liststore_account);
+
+
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass),
gs_auth_dialog_button_add_another_cb);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), gs_auth_dialog_button_cancel_cb);
+ gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), gs_auth_dialog_button_continue_cb);
+}
+
+static void
+gs_auth_dialog_init (GsAuthDialog *self)
+{
+ self->cancellable = g_cancellable_new ();
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+ gtk_widget_grab_focus (self->button_continue);
}
+/* GInitable */
+
+static gboolean
+gs_auth_dialog_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsAuthDialog *self;
+
+ g_return_val_if_fail (GS_IS_AUTH_DIALOG (initable), FALSE);
+
+ self = GS_AUTH_DIALOG (initable);
+
+ self->goa_client = goa_client_new_sync (NULL, error);
+ if (!self->goa_client)
+ return FALSE;
+
+ /* Be ready to other accounts */
+ g_signal_connect (self->goa_client, "account-added", G_CALLBACK (gs_auth_dialog_account_added_cb),
self);
+ g_signal_connect (self->goa_client, "account-removed", G_CALLBACK
(gs_auth_dialog_account_removed_cb), self);
+
+ return TRUE;
+}
+
+static void
+gs_auth_dialog_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = gs_auth_dialog_initable_init;
+}
+
+/* Public API */
+
GtkWidget *
gs_auth_dialog_new (GsPluginLoader *plugin_loader,
GsApp *app,
- const gchar *provider_id,
+ const gchar *auth_id,
GError **error)
{
GsAuthDialog *dialog;
GsAuth *auth;
/* get the authentication provider */
- if (provider_id == NULL) {
+ if (auth_id == NULL) {
g_set_error (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_FAILED,
@@ -336,25 +458,32 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
app != NULL ? gs_app_get_id (app) : NULL);
return NULL;
}
- auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id);
+ auth = gs_plugin_loader_get_auth_by_id (plugin_loader, auth_id);
if (auth == NULL) {
g_set_error (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_NOT_SUPPORTED,
"no auth-provider %s for %s",
- provider_id,
+ auth_id,
app != NULL ? gs_app_get_id (app) : NULL);
return NULL;
}
/* create dialog */
- dialog = g_object_new (GS_TYPE_AUTH_DIALOG,
- "use-header-bar", TRUE,
- NULL);
+ dialog = g_initable_new (GS_TYPE_AUTH_DIALOG,
+ NULL, error,
+ "use-header-bar", FALSE,
+ NULL);
+
+ if (dialog == NULL)
+ return NULL;
+
dialog->plugin_loader = g_object_ref (plugin_loader);
dialog->app = app != NULL ? g_object_ref (app) : NULL;
dialog->auth = g_object_ref (auth);
- gs_auth_dialog_setup (dialog);
+
+ gs_auth_dialog_setup_model (dialog);
+ gs_auth_dialog_check_ui (dialog, FALSE);
return GTK_WIDGET (dialog);
}
diff --git a/src/gs-auth-dialog.h b/src/gs-auth-dialog.h
index 721a307e..63b7877b 100644
--- a/src/gs-auth-dialog.h
+++ b/src/gs-auth-dialog.h
@@ -32,10 +32,10 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GsAuthDialog, gs_auth_dialog, GS, AUTH_DIALOG, GtkDialog)
-GtkWidget *gs_auth_dialog_new (GsPluginLoader *plugin_loader,
- GsApp *app,
- const gchar *provider_id,
- GError **error);
+GtkWidget *gs_auth_dialog_new (GsPluginLoader *plugin_loader,
+ GsApp *app,
+ const gchar *auth_id,
+ GError **error);
G_END_DECLS
diff --git a/src/gs-auth-dialog.ui b/src/gs-auth-dialog.ui
index aec7b247..f96d0461 100644
--- a/src/gs-auth-dialog.ui
+++ b/src/gs-auth-dialog.ui
@@ -1,317 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
+<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
+ <object class="GtkListStore" id="liststore_account">
+ <columns>
+ <!-- column-name Id -->
+ <column type="gchararray"/>
+ <!-- column-name Email -->
+ <column type="gchararray"/>
+ <!-- column-name Account -->
+ <column type="GObject"/>
+ </columns>
+ </object>
<template class="GsAuthDialog" parent="GtkDialog">
<property name="resizable">False</property>
- <property name="modal">True</property>
- <property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
- <property name="deletable">False</property>
+ <child>
+ <placeholder/>
+ </child>
<child internal-child="vbox">
- <object class="GtkBox" id="box_dialog">
+ <object class="GtkBox">
+ <property name="border_width">6</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
- <property name="layout_style">end</property>
<child>
- <placeholder/>
+ <object class="GtkButton" id="button_add_another">
+ <property name="label" translatable="yes">Add another…</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="gs_auth_dialog_button_add_another_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="secondary">True</property>
+ <property name="non_homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_cancel">
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="gs_auth_dialog_button_cancel_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="non_homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_continue">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="gs_auth_dialog_button_continue_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="non_homogeneous">True</property>
+ </packing>
</child>
</object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
</child>
<child>
- <object class="GtkGrid">
- <property name="visible">True</property>
- <property name="border_width">21</property>
- <property name="row_spacing">9</property>
- <property name="column_spacing">21</property>
- <child>
- <object class="GtkStack" id="stack">
+ <object class="GtkInfoBar" id="error_bar">
+ <property name="no_show_all">True</property>
+ <property name="message_type">error</property>
+ <property name="revealed">False</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
<property name="visible">True</property>
- <property name="transition_type">crossfade</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
<child>
- <object class="GtkGrid">
- <property name="name">intro</property>
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="valign">start</property>
- <property name="row_spacing">9</property>
- <property name="column_spacing">9</property>
- <child>
- <object class="GtkLabel" id="label_title">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="label">To continue you need an %NAME% account.</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- <property name="width">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Email address</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_username">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="margin_bottom">15</property>
- <property name="input_purpose">email</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="radiobutton_already">
- <property name="label" translatable="yes">I have an account already</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- <property name="width">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Password</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_password">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="input_purpose">password</property>
- <property name="visibility">False</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="radiobutton_register">
- <property name="label" translatable="yes">I want to register for an account
now</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton_already</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">5</property>
- <property name="width">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="radiobutton_lost_pwd">
- <property name="label" translatable="yes">I have forgotten my password</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">start</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">radiobutton_already</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">6</property>
- <property name="width">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="checkbutton_remember">
- <property name="label" translatable="yes">Sign in automatically next time</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">login</property>
- </packing>
+ <placeholder/>
</child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ </packing>
+ </child>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="spacing">16</property>
<child>
- <object class="GtkGrid">
- <property name="name">2fa</property>
+ <object class="GtkLabel" id="label_error">
<property name="visible">True</property>
- <property name="row_spacing">9</property>
- <property name="column_spacing">9</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Enter your one-time pin for two-factor
authentication.</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- <property name="width">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">PIN</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_pin">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="input_purpose">password</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
+ <property name="justify">fill</property>
+ <property name="wrap">True</property>
+ <property name="width_chars">0</property>
+ <property name="max_width_chars">50</property>
</object>
- <packing>
- <property name="name">2fa</property>
- </packing>
</child>
</object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
</child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
<child>
- <object class="GtkImage" id="image_vendor">
- <property name="visible">False</property>
+ <object class="GtkImage">
+ <property name="visible">True</property>
<property name="halign">start</property>
<property name="valign">start</property>
- <property name="stock">gtk-floppy</property>
+ <property name="icon_name">org.gnome.Software</property>
<property name="icon_size">6</property>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- <property name="height">2</property>
- </packing>
</child>
<child>
- <object class="GtkBox" id="box_error">
- <property name="visible">False</property>
- <property name="spacing">6</property>
+ <object class="GtkBox" id="box_auth">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
<child>
- <object class="GtkImage">
+ <object class="GtkLabel" id="label_header">
+ <property name="name">label_header</property>
<property name="visible">True</property>
- <property name="halign">end</property>
+ <property name="halign">start</property>
<property name="valign">start</property>
- <property name="icon_name">dialog-warning-symbolic</property>
- <property name="use_fallback">True</property>
- <property name="icon_size">5</property>
+ <property name="use_markup">True</property>
+ <property name="justify">fill</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">40</property>
</object>
</child>
<child>
- <object class="GtkLabel" id="label_error">
- <property name="visible">True</property>
+ <object class="GtkComboBox" id="combobox_account">
+ <property name="halign">start</property>
+ <property name="model">liststore_account</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_account">
<property name="halign">start</property>
- <property name="label">The supplied credentials were not correct</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
</object>
</child>
</object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
</child>
</object>
</child>
</object>
</child>
- <child type="titlebar">
- <object class="GtkHeaderBar">
- <property name="visible">True</property>
- <property name="title" translatable="yes">Authenticate</property>
- <child>
- <object class="GtkButton" id="button_cancel">
- <property name="label">gtk-cancel</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="button_continue">
- <property name="label" translatable="yes">Continue</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- </object>
- </child>
</template>
- <object class="GtkSizeGroup" id="sizegroup_buttons">
- <widgets>
- <widget name="button_continue"/>
- <widget name="button_cancel"/>
- </widgets>
- </object>
</interface>
diff --git a/src/gs-page.c b/src/gs-page.c
index aa5321ec..823ce338 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -99,10 +99,10 @@ gs_page_authenticate_cb (GtkDialog *dialog,
void
gs_page_authenticate (GsPage *page,
GsApp *app,
- const gchar *provider_id,
+ const gchar *auth_id,
GCancellable *cancellable,
- GsPageAuthCallback callback,
- gpointer user_data)
+ GsPageAuthCallback callback,
+ gpointer user_data)
{
GsPagePrivate *priv = gs_page_get_instance_private (page);
g_autoptr(GsPageHelper) helper = NULL;
@@ -117,7 +117,7 @@ gs_page_authenticate (GsPage *page,
dialog = gs_auth_dialog_new (priv->plugin_loader,
app,
- provider_id,
+ auth_id,
&error);
if (dialog == NULL) {
g_warning ("%s", error->message);
diff --git a/src/gs-page.h b/src/gs-page.h
index 539a0b58..874e8cbc 100644
--- a/src/gs-page.h
+++ b/src/gs-page.h
@@ -63,7 +63,7 @@ void gs_page_set_header_end_widget (GsPage *page,
GtkWidget *widget);
void gs_page_authenticate (GsPage *page,
GsApp *app,
- const gchar *provider_id,
+ const gchar *auth_id,
GCancellable *cancellable,
GsPageAuthCallback callback,
gpointer user_data);
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 85d66a31..03aeba9c 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -656,86 +656,104 @@ static void
signin_activated_cb (GSimpleAction *action, GVariant *parameter, GsShell *shell)
{
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
- const gchar *action_name, *provider_id;
+ const gchar *action_name, *auth_id;
GsAuth *auth;
action_name = g_action_get_name (G_ACTION (action));
g_return_if_fail (g_str_has_prefix (action_name, "signin-"));
- provider_id = action_name + strlen ("signin-");
+ auth_id = action_name + strlen ("signin-");
- auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, provider_id);
+ auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, auth_id);
g_return_if_fail (auth != NULL);
gs_page_authenticate (priv->page, NULL,
- gs_auth_get_provider_id (auth),
+ gs_auth_get_auth_id (auth),
priv->cancellable,
NULL, NULL);
}
-static void
-gs_shell_logout_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
-{
- GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
- g_autoptr(GError) error = NULL;
-
- if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
- g_warning ("failed to logout: %s", error->message);
- return;
- }
-}
-
static void
signout_activated_cb (GSimpleAction *action, GVariant *parameter, GsShell *shell)
{
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
- const gchar *action_name, *provider_id;
+ const gchar *action_name, *auth_id;
g_autoptr(GsPluginJob) plugin_job = NULL;
GsAuth *auth;
action_name = g_action_get_name (G_ACTION (action));
g_return_if_fail (g_str_has_prefix (action_name, "signout-"));
- provider_id = action_name + strlen ("signout-");
+ auth_id = action_name + strlen ("signout-");
- auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, provider_id);
+ auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, auth_id);
g_return_if_fail (auth != NULL);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGOUT,
- "interactive", TRUE,
- "auth", auth,
- NULL);
-
- gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job,
- priv->cancellable,
- gs_shell_logout_cb,
- shell);
+ gs_auth_set_goa_object (auth, NULL);
}
static void
-menu_button_clicked_cb (GtkButton *button, GsShell *shell)
+gs_shell_reload_auth_menus (GsShell *shell)
{
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GMenu *accounts_menu;
GPtrArray *auth_array;
+ accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
+ g_menu_remove_all (accounts_menu);
+
auth_array = gs_plugin_loader_get_auths (priv->plugin_loader);
for (guint i = 0; i < auth_array->len; i++) {
GsAuth *auth = g_ptr_array_index (auth_array, i);
gboolean logged_in;
g_autofree gchar *signin_action_name = NULL;
GSimpleAction *signin_action;
+ g_autofree gchar *signin_target = NULL;
g_autofree gchar *signout_action_name = NULL;
GSimpleAction *signout_action;
+ g_autofree gchar *signout_target = NULL;
+ GoaObject *goa_object;
+ g_autofree gchar *signin_label = NULL;
+ g_autofree gchar *signout_label = NULL;
+ g_autoptr(GMenu) auth_menu = NULL;
+ g_autoptr(GMenuItem) signin_item = NULL;
+ g_autoptr(GMenuItem) signout_item = NULL;
+
+
+ goa_object = gs_auth_peek_goa_object (auth);
+ logged_in = goa_object != NULL;
- logged_in = gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID);
+ auth_menu = g_menu_new ();
+ accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
+ g_menu_append_section (accounts_menu, gs_auth_get_provider_name (auth), G_MENU_MODEL
(auth_menu));
- signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_provider_id (auth));
+ signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_auth_id (auth));
signin_action = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP
(priv->auth_actions), signin_action_name));
g_simple_action_set_enabled (signin_action, !logged_in);
- signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_provider_id (auth));
+ signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_auth_id (auth));
signout_action = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP
(priv->auth_actions), signout_action_name));
g_simple_action_set_enabled (signout_action, logged_in);
+
+
+ if (logged_in) {
+ GoaAccount *goa_account = goa_object_peek_account (goa_object);
+
+ /* TRANSLATORS: menu item that signs into the named account with a particular
username */
+ signin_label = g_strdup_printf (_("Signed in as %s"),
+ goa_account_get_presentation_identity (goa_account));
+ } else {
+ /* TRANSLATORS: menu item that signs into the named account */
+ signin_label = g_strdup_printf (_("Sign in…"));
+ }
+
+ signin_target = g_strdup_printf ("auth.%s", signin_action_name);
+ signin_item = g_menu_item_new (signin_label, signin_target);
+ g_menu_append_item (auth_menu, signin_item);
+
+ /* TRANSLATORS: menu item for signing out from the named account */
+ signout_label = g_strdup_printf (_("Sign out"));
+ signout_target = g_strdup_printf ("auth.%s", signout_action_name);
+ signout_item = g_menu_item_new (signout_label, signout_target);
+ g_menu_append_item (auth_menu, signout_item);
}
}
@@ -1030,7 +1048,6 @@ gs_shell_show_event_refresh (GsShell *shell, GsPluginEvent *event)
buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
break;
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification */
g_string_append (str, _("Unable to download updates: "
"authentication was required"));
@@ -1093,7 +1110,6 @@ gs_shell_show_event_purchase (GsShell *shell, GsPluginEvent *event)
str_app = gs_shell_get_title_from_app (app);
switch (error->code) {
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification,
* where the %s is the application name (e.g. "GIMP") */
g_string_append_printf (str, _("Unable to purchase %s: "
@@ -1208,7 +1224,6 @@ gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
break;
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification */
g_string_append_printf (str, _("Unable to install %s: "
"authentication was required"),
@@ -1229,35 +1244,6 @@ gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
"install software"),
str_app);
break;
- case GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED:
- case GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED:
- if (origin != NULL) {
- const gchar *url_homepage;
-
- /* TRANSLATORS: failure text for the in-app notification,
- * the %s is the name of the authentication service,
- * e.g. "Ubuntu One" */
- g_string_append_printf (str, _("Your %s account has been suspended."),
- gs_app_get_name (origin));
- g_string_append (str, " ");
- /* TRANSLATORS: failure text for the in-app notification */
- g_string_append (str, _("It is not possible to install "
- "software until this has been resolved."));
- url_homepage = gs_app_get_url (origin, AS_URL_KIND_HOMEPAGE);
- if (url_homepage != NULL) {
- g_autofree gchar *url = NULL;
- url = g_strdup_printf ("<a href=\"%s\">%s</a>",
- url_homepage,
- url_homepage);
- /* TRANSLATORS: failure text for the in-app notification,
- * where the %s is the clickable link (e.g.
- * "http://example.com/what-did-i-do-wrong/") */
- msg = g_strdup_printf (_("For more information, visit %s."),
- url);
- g_string_append_printf (str, " %s", msg);
- }
- }
- break;
case GS_PLUGIN_ERROR_AC_POWER_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification,
* where the %s is the application name (e.g. "Dell XPS 13") */
@@ -1342,7 +1328,6 @@ gs_shell_show_event_update (GsShell *shell, GsPluginEvent *event)
buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
break;
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification,
* where the %s is the application name (e.g. "GIMP") */
g_string_append_printf (str, _("Unable to update %s: "
@@ -1447,7 +1432,6 @@ gs_shell_show_event_upgrade (GsShell *shell, GsPluginEvent *event)
buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
break;
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification,
* where the %s is the distro name (e.g. "Fedora 25") */
g_string_append_printf (str, _("Unable to upgrade to %s: "
@@ -1519,7 +1503,6 @@ gs_shell_show_event_remove (GsShell *shell, GsPluginEvent *event)
str_app = gs_shell_get_title_from_app (app);
switch (error->code) {
case GS_PLUGIN_ERROR_AUTH_REQUIRED:
- case GS_PLUGIN_ERROR_PIN_REQUIRED:
/* TRANSLATORS: failure text for the in-app notification,
* where the %s is the application name (e.g. "GIMP") */
g_string_append_printf (str, _("Unable to remove %s: authentication was required"),
@@ -2021,10 +2004,10 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
shell);
/* show the account popover when clicking on the account button */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "menu_button"));
+ /* widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "menu_button"));
g_signal_connect (widget, "clicked",
G_CALLBACK (menu_button_clicked_cb),
- shell);
+ shell); */
/* setup buttons */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
@@ -2115,58 +2098,25 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
auth_array = gs_plugin_loader_get_auths (priv->plugin_loader);
for (guint i = 0; i < auth_array->len; i++) {
GsAuth *auth = g_ptr_array_index (auth_array, i);
- GMenu *accounts_menu;
- gboolean logged_in;
- g_autoptr(GMenu) auth_menu = NULL;
g_autoptr(GSimpleAction) signin_action = NULL;
g_autofree gchar *signin_action_name = NULL;
- g_autoptr(GMenuItem) signin_item = NULL;
- g_autofree gchar *signin_label = NULL;
- g_autofree gchar *signin_target = NULL;
g_autoptr(GSimpleAction) signout_action = NULL;
g_autofree gchar *signout_action_name = NULL;
- g_autoptr(GMenuItem) signout_item = NULL;
- g_autofree gchar *signout_label = NULL;
- g_autofree gchar *signout_target = NULL;
-
- logged_in = gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID);
- signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_provider_id (auth));
+ signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_auth_id (auth));
signin_action = g_simple_action_new (signin_action_name, NULL);
- g_simple_action_set_enabled (signin_action, !logged_in);
g_signal_connect (signin_action, "activate", G_CALLBACK (signin_activated_cb), shell);
g_action_map_add_action (G_ACTION_MAP (priv->auth_actions), G_ACTION (signin_action));
- signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_provider_id (auth));
+ signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_auth_id (auth));
signout_action = g_simple_action_new (signout_action_name, NULL);
- g_simple_action_set_enabled (signout_action, logged_in);
g_signal_connect (signout_action, "activate", G_CALLBACK (signout_activated_cb), shell);
g_action_map_add_action (G_ACTION_MAP (priv->auth_actions), G_ACTION (signout_action));
- auth_menu = g_menu_new ();
- accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
- g_menu_append_section (accounts_menu, NULL, G_MENU_MODEL (auth_menu));
-
- if (logged_in) {
- /* TRANSLATORS: menu item that signs into the named account with a particular
username */
- signin_label = g_strdup_printf (_("Signed in into %s as %s"),
- gs_auth_get_provider_name (auth),
- gs_auth_get_username (auth));
- } else {
- /* TRANSLATORS: menu item that signs into the named account */
- signin_label = g_strdup_printf (_("Sign in to %s…"),
- gs_auth_get_provider_name (auth));
- }
- signin_target = g_strdup_printf ("auth.%s", signin_action_name);
- signin_item = g_menu_item_new (signin_label, signin_target);
- g_menu_append_item (auth_menu, signin_item);
-
- /* TRANSLATORS: menu item for signing out from the named account */
- signout_label = g_strdup_printf (_("Sign out from %s"),
- gs_auth_get_provider_name (auth));
- signout_target = g_strdup_printf ("auth.%s", signout_action_name);
- signout_item = g_menu_item_new (signout_label, signout_target);
- g_menu_append_item (auth_menu, signout_item);
+ g_signal_connect_object (auth, "changed",
+ G_CALLBACK (gs_shell_reload_auth_menus),
+ shell, G_CONNECT_SWAPPED);
+ gs_shell_reload_auth_menus (shell);
}
/* show loading page, which triggers the initial refresh */
diff --git a/src/meson.build b/src/meson.build
index ebcaaa98..aafc9b7a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -74,10 +74,10 @@ gnome_software_dependencies = [
appstream_glib,
gio_unix,
gmodule,
+ goa,
gtk,
json_glib,
libm,
- libsecret,
libsoup
]
@@ -296,10 +296,10 @@ if get_option('tests')
appstream_glib,
gio_unix,
gmodule,
+ goa,
gtk,
json_glib,
libm,
- libsecret,
libsoup,
],
link_with : [
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]