[evolution-data-server] I#196 - Use default OAuth2 services on scratch sources



commit 37f651a35b84c499f647f366ee3cd66c1cdc9564
Author: Milan Crha <mcrha redhat com>
Date:   Mon Feb 8 15:48:30 2021 +0100

    I#196 - Use default OAuth2 services on scratch sources
    
    When creating a new calendar or such, the ESource is a scratch source, which
    means it doesn't have its counter part on the evolution-source-registry side.
    The OAuth2 tokens are usually received through the source registry, which resulted
    in an error "Data source “Personal” does not support OAuth 2.0 authentication".
    The sources created in Evolution do not need any special OAuth2 provider,
    thus it's possible to use the built-in services only.
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/196

 src/libebackend/e-server-side-source.c     |  23 ++++--
 src/libebackend/e-source-registry-server.c | 117 ++++++++++++++++++++++++++++-
 src/libebackend/e-source-registry-server.h |   3 +
 src/libedataserver/e-source-registry.c     |  53 ++++++++++---
 src/libedataserver/e-source.c              |  35 +++++++++
 5 files changed, 211 insertions(+), 20 deletions(-)
---
diff --git a/src/libebackend/e-server-side-source.c b/src/libebackend/e-server-side-source.c
index f8c01a57d..6f646f11c 100644
--- a/src/libebackend/e-server-side-source.c
+++ b/src/libebackend/e-server-side-source.c
@@ -1470,13 +1470,22 @@ server_side_source_get_oauth2_access_token_sync (ESource *source,
                E_SERVER_SIDE_SOURCE (source));
 
        if (oauth2_support == NULL) {
-               g_set_error (
-                       error, G_IO_ERROR,
-                       G_IO_ERROR_NOT_SUPPORTED,
-                       _("Data source “%s” does not "
-                       "support OAuth 2.0 authentication"),
-                       e_source_get_display_name (source));
-               return FALSE;
+               ESourceRegistryServer *server;
+
+               server = e_server_side_source_get_server (E_SERVER_SIDE_SOURCE (source));
+
+               if (server)
+                       oauth2_support = e_source_registry_server_ref_oauth2_support (server);
+
+               if (!oauth2_support) {
+                       g_set_error (
+                               error, G_IO_ERROR,
+                               G_IO_ERROR_NOT_SUPPORTED,
+                               _("Data source “%s” does not "
+                               "support OAuth 2.0 authentication"),
+                               e_source_get_display_name (source));
+                       return FALSE;
+               }
        }
 
        success = e_oauth2_support_get_access_token_sync (
diff --git a/src/libebackend/e-source-registry-server.c b/src/libebackend/e-source-registry-server.c
index 899554821..0baeaf0fe 100644
--- a/src/libebackend/e-source-registry-server.c
+++ b/src/libebackend/e-source-registry-server.c
@@ -82,10 +82,11 @@ enum {
 
 static guint signals[LAST_SIGNAL];
 
-G_DEFINE_TYPE_WITH_PRIVATE (
-       ESourceRegistryServer,
-       e_source_registry_server,
-       E_TYPE_DATA_FACTORY)
+static void e_source_registry_server_oauth2_support_init (EOAuth2SupportInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ESourceRegistryServer, e_source_registry_server, E_TYPE_DATA_FACTORY,
+       G_ADD_PRIVATE (ESourceRegistryServer)
+       G_IMPLEMENT_INTERFACE (E_TYPE_OAUTH2_SUPPORT, e_source_registry_server_oauth2_support_init))
 
 /* GDestroyNotify callback for 'sources' values */
 static void
@@ -755,6 +756,46 @@ source_registry_server_adopt_orphans (ESourceRegistryServer *server,
        }
 }
 
+static GObject *server_singleton = NULL;
+G_LOCK_DEFINE_STATIC (server_singleton);
+
+static void
+server_singleton_weak_ref_cb (gpointer user_data,
+                             GObject *object)
+{
+       G_LOCK (server_singleton);
+
+       g_warn_if_fail (object == server_singleton);
+       server_singleton = NULL;
+
+       G_UNLOCK (server_singleton);
+}
+
+static GObject *
+source_registry_server_constructor (GType type,
+                                   guint n_construct_params,
+                                   GObjectConstructParam *construct_params)
+{
+       GObject *object;
+
+       G_LOCK (server_singleton);
+
+       if (server_singleton) {
+               object = g_object_ref (server_singleton);
+       } else {
+               object = G_OBJECT_CLASS (e_source_registry_server_parent_class)->constructor (type, 
n_construct_params, construct_params);
+
+               if (object)
+                       g_object_weak_ref (object, server_singleton_weak_ref_cb, NULL);
+
+               server_singleton = object;
+       }
+
+       G_UNLOCK (server_singleton);
+
+       return object;
+}
+
 static void
 source_registry_server_constructed (GObject *object)
 {
@@ -973,6 +1014,42 @@ source_registry_server_any_true (GSignalInvocationHint *ihint,
        return TRUE;
 }
 
+static gboolean
+e_source_registry_server_get_access_token_sync (EOAuth2Support *support,
+                                               ESource *source,
+                                               GCancellable *cancellable,
+                                               gchar **out_access_token,
+                                               gint *out_expires_in,
+                                               GError **error)
+{
+       EOAuth2ServiceRefSourceFunc ref_source;
+       ESourceRegistryServer *server;
+       EOAuth2Service *service;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (support), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       server = E_SOURCE_REGISTRY_SERVER (support);
+       service = e_oauth2_services_find (server->priv->oauth2_services, source);
+
+       if (!service) {
+               g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                       _("Data source “%s” does not support OAuth 2.0 authentication"),
+                       e_source_get_display_name (source));
+               return FALSE;
+       }
+
+       ref_source = (EOAuth2ServiceRefSourceFunc) e_source_registry_server_ref_source;
+
+       success = e_oauth2_service_get_access_token_sync (service, source, ref_source, server,
+               out_access_token, out_expires_in, cancellable, error);
+
+       g_clear_object (&service);
+
+       return success;
+}
+
 static GDBusInterfaceSkeleton *
 source_registry_server_get_dbus_interface_skeleton (EDBusServer *server)
 {
@@ -999,6 +1076,7 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
                modules_directory = g_strdup (modules_directory_env);
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->constructor = source_registry_server_constructor;
        object_class->constructed = source_registry_server_constructed;
        object_class->dispose = source_registry_server_dispose;
        object_class->finalize = source_registry_server_finalize;
@@ -1119,6 +1197,12 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
                G_TYPE_STRING);
 }
 
+static void
+e_source_registry_server_oauth2_support_init (EOAuth2SupportInterface *iface)
+{
+       iface->get_access_token_sync = e_source_registry_server_get_access_token_sync;
+}
+
 static void
 e_source_registry_server_init (ESourceRegistryServer *server)
 {
@@ -2068,3 +2152,28 @@ e_source_registry_server_ref_backend_factory (ESourceRegistryServer *server,
         * We specify this in source_registry_server_class_init(). */
        return E_COLLECTION_BACKEND_FACTORY (factory);
 }
+
+/**
+ * e_source_registry_server_ref_oauth2_support:
+ * @server: an #ESourceRegistryServer
+ *
+ * Returns the default #EOAuth2Support implementation, which can be used when
+ * the source doesn't have it overwritten.
+ *
+ * Free the returned object with g_object_unref(), when no longer needed.
+ *
+ * Returns: (transfer full) (nullable): the default #EOAuth2Support,
+ *    or %NULL, when none exists
+ *
+ * Since: 3.40
+ **/
+EOAuth2Support *
+e_source_registry_server_ref_oauth2_support (ESourceRegistryServer *server)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
+
+       if (!server->priv->oauth2_services)
+               return NULL;
+
+       return g_object_ref (E_OAUTH2_SUPPORT (server));
+}
diff --git a/src/libebackend/e-source-registry-server.h b/src/libebackend/e-source-registry-server.h
index e53b33acb..fbc8ff62c 100644
--- a/src/libebackend/e-source-registry-server.h
+++ b/src/libebackend/e-source-registry-server.h
@@ -28,6 +28,7 @@
 #include <libebackend/e-data-factory.h>
 #include <libebackend/e-collection-backend.h>
 #include <libebackend/e-collection-backend-factory.h>
+#include <libebackend/e-oauth2-support.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SOURCE_REGISTRY_SERVER \
@@ -159,6 +160,8 @@ ECollectionBackendFactory *
                e_source_registry_server_ref_backend_factory
                                                (ESourceRegistryServer *server,
                                                 ESource *source);
+EOAuth2Support *e_source_registry_server_ref_oauth2_support
+                                               (ESourceRegistryServer *server);
 
 #ifndef EDS_DISABLE_DEPRECATED
 gboolean       e_source_registry_server_load_all
diff --git a/src/libedataserver/e-source-registry.c b/src/libedataserver/e-source-registry.c
index 8e73c8930..9664bccf4 100644
--- a/src/libedataserver/e-source-registry.c
+++ b/src/libedataserver/e-source-registry.c
@@ -190,15 +190,10 @@ static guint signals[LAST_SIGNAL];
 
 /* By default, the GAsyncInitable interface calls GInitable.init()
  * from a separate thread, so we only have to override GInitable. */
-G_DEFINE_TYPE_WITH_CODE (
-       ESourceRegistry,
-       e_source_registry,
-       G_TYPE_OBJECT,
+G_DEFINE_TYPE_WITH_CODE (ESourceRegistry, e_source_registry, G_TYPE_OBJECT,
        G_ADD_PRIVATE (ESourceRegistry)
-       G_IMPLEMENT_INTERFACE (
-               G_TYPE_INITABLE, e_source_registry_initable_init)
-       G_IMPLEMENT_INTERFACE (
-               G_TYPE_ASYNC_INITABLE, NULL))
+       G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, e_source_registry_initable_init)
+       G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, NULL))
 
 static void
 async_context_free (AsyncContext *async_context)
@@ -1291,6 +1286,46 @@ source_registry_get_property (GObject *object,
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
+static GObject *registry_singleton = NULL;
+G_LOCK_DEFINE_STATIC (registry_singleton);
+
+static void
+registry_singleton_weak_ref_cb (gpointer user_data,
+                               GObject *object)
+{
+       G_LOCK (registry_singleton);
+
+       g_warn_if_fail (object == registry_singleton);
+       registry_singleton = NULL;
+
+       G_UNLOCK (registry_singleton);
+}
+
+static GObject *
+source_registry_constructor (GType type,
+                            guint n_construct_params,
+                            GObjectConstructParam *construct_params)
+{
+       GObject *object;
+
+       G_LOCK (registry_singleton);
+
+       if (registry_singleton) {
+               object = g_object_ref (registry_singleton);
+       } else {
+               object = G_OBJECT_CLASS (e_source_registry_parent_class)->constructor (type, 
n_construct_params, construct_params);
+
+               if (object)
+                       g_object_weak_ref (object, registry_singleton_weak_ref_cb, NULL);
+
+               registry_singleton = object;
+       }
+
+       G_UNLOCK (registry_singleton);
+
+       return object;
+}
+
 static void
 source_registry_dispose (GObject *object)
 {
@@ -1469,6 +1504,7 @@ e_source_registry_class_init (ESourceRegistryClass *class)
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = source_registry_set_property;
        object_class->get_property = source_registry_get_property;
+       object_class->constructor = source_registry_constructor;
        object_class->dispose = source_registry_dispose;
        object_class->finalize = source_registry_finalize;
 
@@ -3807,4 +3843,3 @@ e_source_registry_set_default_for_extension_name (ESourceRegistry *registry,
                e_source_registry_set_default_task_list (
                        registry, default_source);
 }
-
diff --git a/src/libedataserver/e-source.c b/src/libedataserver/e-source.c
index 353a3e748..f87e54bab 100644
--- a/src/libedataserver/e-source.c
+++ b/src/libedataserver/e-source.c
@@ -74,9 +74,11 @@
 #include "e-dbus-source.h"
 
 #include "e-data-server-util.h"
+#include "e-oauth2-services.h"
 #include "e-secret-store.h"
 #include "e-source-enumtypes.h"
 #include "e-source-extension.h"
+#include "e-source-registry.h"
 #include "e-uid.h"
 
 /* built-in extension types */
@@ -1784,6 +1786,39 @@ source_get_oauth2_access_token_sync (ESource *source,
                g_object_unref (dbus_object);
        }
 
+       if (!dbus_interface) {
+               ESourceRegistry *registry;
+
+               registry = e_source_registry_new_sync (NULL, NULL);
+
+               if (registry) {
+                       EOAuth2Services *oauth2_services;
+                       EOAuth2Service *service = NULL;
+
+                       oauth2_services = e_source_registry_get_oauth2_services (registry);
+
+                       if (oauth2_services)
+                               service = e_oauth2_services_find (oauth2_services, source);
+
+                       if (service) {
+                               EOAuth2ServiceRefSourceFunc ref_source;
+                               gboolean success;
+
+                               ref_source = (EOAuth2ServiceRefSourceFunc) e_source_registry_ref_source;
+
+                               success = e_oauth2_service_get_access_token_sync (service, source, 
ref_source, registry,
+                                       out_access_token, out_expires_in, cancellable, error);
+
+                               g_clear_object (&service);
+                               g_object_unref (registry);
+
+                               return success;
+                       }
+
+                       g_object_unref (registry);
+               }
+       }
+
        if (dbus_interface == NULL) {
                g_set_error (
                        error, G_IO_ERROR,


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