[libsecret/wip/dueno/backend: 10/13] secret-backend: New interface to represent password storage backend



commit 7608084cb03e33f4f4743d05887138ffa229fb39
Author: Daiki Ueno <dueno src gnome org>
Date:   Sat Jun 29 16:56:03 2019 +0200

    secret-backend: New interface to represent password storage backend
    
    This interface provides a separation between the
    frontend (secret_password*) and the backend (SecretService).  That
    makes it easier to replace SecretService with a custom backend
    implementation.

 docs/reference/libsecret/libsecret-sections.txt |  14 ++
 libsecret/Makefile.am                           |   2 +
 libsecret/Secret-1.metadata                     |   6 +
 libsecret/meson.build                           |   2 +
 libsecret/secret-backend.c                      | 265 ++++++++++++++++++++++++
 libsecret/secret-backend.h                      | 111 ++++++++++
 6 files changed, 400 insertions(+)
---
diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt
index f811b9d..1b225fe 100644
--- a/docs/reference/libsecret/libsecret-sections.txt
+++ b/docs/reference/libsecret/libsecret-sections.txt
@@ -366,6 +366,20 @@ secret_attributes_buildv
 <FILE>SecretGenPrompt</FILE>
 </SECTION>
 
+<SECTION>
+<FILE>secret-backend</FILE>
+SECRET_BACKEND_EXTENSION_POINT_NAME
+SECRET_TYPE_BACKEND
+SECRET_TYPE_BACKEND_FLAGS
+SECRET_TYPE_SCHEMA_TYPE
+SecretBackend
+SecretBackendFlags
+SecretBackendInterface
+secret_backend_flags_get_type
+secret_backend_get
+secret_backend_get_finish
+</SECTION>
+
 <SECTION>
 <FILE>secret-version</FILE>
 SECRET_CHECK_VERSION
diff --git a/libsecret/Makefile.am b/libsecret/Makefile.am
index 0e661b8..0e34ea3 100644
--- a/libsecret/Makefile.am
+++ b/libsecret/Makefile.am
@@ -7,6 +7,7 @@ incdir = $(includedir)/libsecret-@SECRET_MAJOR@/libsecret
 libsecret_HEADS = \
        libsecret/secret.h \
        libsecret/secret-attributes.h \
+       libsecret/secret-backend.h \
        libsecret/secret-collection.h \
        libsecret/secret-item.h \
        libsecret/secret-password.h \
@@ -38,6 +39,7 @@ libsecret_BUILT = \
 
 libsecret_PUBLIC = \
        libsecret/secret-attributes.h libsecret/secret-attributes.c \
+       libsecret/secret-backend.h libsecret/secret-backend.c \
        libsecret/secret-collection.h libsecret/secret-collection.c \
        libsecret/secret-item.h libsecret/secret-item.c \
        libsecret/secret-methods.c \
diff --git a/libsecret/Secret-1.metadata b/libsecret/Secret-1.metadata
index bc9e364..3f01645 100644
--- a/libsecret/Secret-1.metadata
+++ b/libsecret/Secret-1.metadata
@@ -66,3 +66,9 @@ Service
   .prompt_at_dbus_path_sync skip=false nullable=true
   .prompt_at_dbus_path skip=false
   .prompt_at_dbus_path_finish skip=false nullable=true
+
+Backend
+  .store skip=true
+  .lookup skip=true
+  .clear skip=true
+  .search skip=true
diff --git a/libsecret/meson.build b/libsecret/meson.build
index 60fa11e..165d06f 100644
--- a/libsecret/meson.build
+++ b/libsecret/meson.build
@@ -2,6 +2,7 @@ installed_headers_subdir = join_paths('libsecret-@0@'.format(api_version_major),
 
 libsecret_sources = [
   'secret-attributes.c',
+  'secret-backend.c',
   'secret-collection.c',
   'secret-item.c',
   'secret-methods.c',
@@ -20,6 +21,7 @@ libsecret_sources = [
 libsecret_headers = [
   'secret.h',
   'secret-attributes.h',
+  'secret-backend.h',
   'secret-collection.h',
   'secret-item.h',
   'secret-password.h',
diff --git a/libsecret/secret-backend.c b/libsecret/secret-backend.c
new file mode 100644
index 0000000..aece85d
--- /dev/null
+++ b/libsecret/secret-backend.c
@@ -0,0 +1,265 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Daiki Ueno
+ */
+
+#include "config.h"
+
+#include "secret-backend.h"
+#include "secret-private.h"
+
+#include "libsecret/secret-enum-types.h"
+
+/**
+ * SECTION:secret-backend
+ * @title: SecretBackend
+ * @short_description: A backend implementation of password storage
+ *
+ * #SecretBackend represents a backend implementation of password
+ * storage.
+ *
+ * Stability: Stable
+ */
+
+/**
+ * SecretBackend:
+ *
+ * An object representing a backend implementation of password storage.
+ */
+
+/**
+ * SecretBackendInterface:
+ * @parent_iface: the parent interface
+ * @ensure_for_flags: implementation of reinitialization step in constructor, optional
+ * @ensure_for_flags_finish: implementation of reinitialization step in constructor, optional
+ * @store: implementation of secret_password_store(), required
+ * @store_finish: implementation of secret_password_store_finish(), required
+ * @lookup: implementation of secret_password_lookup(), required
+ * @lookup_finish: implementation of secret_password_lookup_finish(), required
+ * @clear: implementation of secret_password_clear(), required
+ * @clear_finish: implementation of secret_password_clear_finish(), required
+ * @search: implementation of secret_password_search(), required
+ * @search_finish: implementation of secret_password_search_finish(), required
+ *
+ * The interface for #SecretBackend.
+ */
+
+/**
+ * SecretBackendFlags:
+ * @SECRET_BACKEND_NONE: no flags for initializing the #SecretBackend
+ * @SECRET_BACKEND_OPEN_SESSION: establish a session for transfer of secrets
+ *                               while initializing the #SecretBackend
+ * @SECRET_BACKEND_LOAD_COLLECTIONS: load collections while initializing the
+ *                                   #SecretBackend
+ *
+ * Flags which determine which parts of the #SecretBackend are initialized.
+ */
+
+G_DEFINE_INTERFACE_WITH_CODE (SecretBackend, secret_backend, G_TYPE_OBJECT,
+                             g_type_interface_add_prerequisite(g_define_type_id, G_TYPE_ASYNC_INITABLE);
+);
+
+static void
+secret_backend_default_init (SecretBackendInterface *iface)
+{
+       /**
+        * SecretBackend:flags:
+        *
+        * A set of flags describing which parts of the secret backend have
+        * been initialized.
+        */
+       g_object_interface_install_property (iface,
+                    g_param_spec_flags ("flags", "Flags", "Service flags",
+                                        secret_service_flags_get_type (), SECRET_SERVICE_NONE,
+                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_STATIC_STRINGS));
+}
+
+void
+_secret_backend_ensure_extension_point (void)
+{
+       GIOExtensionPoint *ep;
+       static gboolean registered = FALSE;
+
+       if (registered)
+               return;
+
+       ep = g_io_extension_point_register (SECRET_BACKEND_EXTENSION_POINT_NAME);
+       g_io_extension_point_set_required_type (ep, SECRET_TYPE_BACKEND);
+
+       registered = TRUE;
+}
+
+G_LOCK_DEFINE (backend_instance);
+static gpointer backend_instance = NULL;
+
+static SecretBackend *
+backend_get_instance (void)
+{
+       SecretBackend *instance = NULL;
+
+       G_LOCK (backend_instance);
+       if (backend_instance != NULL)
+               instance = g_object_ref (backend_instance);
+       G_UNLOCK (backend_instance);
+
+       return instance;
+}
+
+static GType
+backend_get_impl_type (void)
+{
+       const gchar *envvar = g_getenv ("SECRET_BACKEND");
+       const gchar *extension_name;
+       GIOExtension *e;
+       GIOExtensionPoint *ep;
+
+       if (envvar == NULL || *envvar == '\0')
+               extension_name = "service";
+       else
+               extension_name = envvar;
+
+       ep = g_io_extension_point_lookup (SECRET_BACKEND_EXTENSION_POINT_NAME);
+       e = g_io_extension_point_get_extension_by_name (ep, extension_name);
+       if (e == NULL) {
+               g_warning ("Backend extension \"%s\" from SECRET_BACKEND_EXTENSION_POINT_NAME environment 
variable not found.", extension_name);
+               return G_TYPE_NONE;
+       }
+
+       return g_io_extension_get_type (e);
+}
+
+static void
+on_ensure_for_flags (GObject *source_object,
+                    GAsyncResult *result,
+                    gpointer user_data)
+{
+       SecretBackendInterface *iface;
+       SecretBackend *self = SECRET_BACKEND (source_object);
+       GTask *task = G_TASK (user_data);
+       GError *error = NULL;
+
+       iface = SECRET_BACKEND_GET_IFACE (self);
+       if (iface->ensure_for_flags_finish) {
+               if (!iface->ensure_for_flags_finish (self, result, &error)) {
+                       g_task_return_error (task, error);
+                       g_object_unref (task);
+                       return;
+               }
+       }
+
+       g_task_return_boolean (task, TRUE);
+       g_object_unref (task);
+}
+
+/**
+ * secret_backend_get:
+ * @flags: flags for which service functionality to ensure is initialized
+ * @cancellable: optional cancellation object
+ * @callback: called when the operation completes
+ * @user_data: data to be passed to the callback
+ *
+ * Get a #SecretBackend instance. If such a backend already exists,
+ * then the same backend is returned.
+ *
+ * If @flags contains any flags of which parts of the secret backend to
+ * ensure are initialized, then those will be initialized before completing.
+ *
+ * This method will return immediately and complete asynchronously.
+ */
+void
+secret_backend_get (SecretBackendFlags flags,
+                   GCancellable *cancellable,
+                   GAsyncReadyCallback callback,
+                   gpointer user_data)
+{
+       SecretBackend *backend = NULL;
+       SecretBackendInterface *iface;
+       GTask *task;
+
+       backend = backend_get_instance ();
+
+       /* Create a whole new backend */
+       if (backend == NULL) {
+               GType impl_type = backend_get_impl_type ();
+               g_return_if_fail (g_type_is_a (impl_type, G_TYPE_ASYNC_INITABLE));
+               g_async_initable_new_async (impl_type,
+                                           G_PRIORITY_DEFAULT,
+                                           cancellable, callback, user_data,
+                                           "flags", flags,
+                                           NULL);
+
+       /* Just have to ensure that the backend matches flags */
+       } else {
+               task = g_task_new (backend, cancellable, callback, user_data);
+               iface = SECRET_BACKEND_GET_IFACE (backend);
+               if (iface->ensure_for_flags) {
+                       g_task_set_source_tag (task, secret_backend_get);
+                       iface->ensure_for_flags (backend, flags, cancellable,
+                                                on_ensure_for_flags, task);
+               } else {
+                       g_task_return_boolean (task, TRUE);
+                       g_object_unref (task);
+               }
+               g_object_unref (backend);
+       }
+}
+
+/**
+ * secret_backend_get_finish:
+ * @result: the asynchronous result passed to the callback
+ * @error: location to place an error on failure
+ *
+ * Complete an asynchronous operation to get a #SecretBackend.
+ *
+ * Returns: (transfer full): a new reference to a #SecretBackend proxy, which
+ *          should be released with g_object_unref().
+ */
+SecretBackend *
+secret_backend_get_finish (GAsyncResult *result,
+                          GError **error)
+{
+       GTask *task;
+       GObject *backend = NULL;
+       GObject *source_object;
+
+       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       task = G_TASK (result);
+       source_object = g_task_get_source_object (task);
+
+       g_return_val_if_fail (g_task_is_valid (result, source_object), NULL);
+
+       /* Just ensuring that the backend matches flags */
+       if (g_task_get_source_tag (task) == secret_backend_get) {
+               if (g_task_had_error (task)) {
+                       g_task_propagate_pointer (task, error);
+               } else {
+                       backend = g_object_ref (source_object);
+               }
+
+       /* Creating a whole new backend */
+       } else {
+               backend = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+               if (backend) {
+                       G_LOCK (backend_instance);
+                       if (backend_instance == NULL)
+                               backend_instance = backend;
+                       G_UNLOCK (backend_instance);
+               }
+       }
+
+       if (backend == NULL)
+               return NULL;
+
+       return SECRET_BACKEND (backend);
+}
diff --git a/libsecret/secret-backend.h b/libsecret/secret-backend.h
new file mode 100644
index 0000000..7dae506
--- /dev/null
+++ b/libsecret/secret-backend.h
@@ -0,0 +1,111 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Daiki Ueno
+ */
+
+#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION)
+#error "Only <libsecret/secret.h> can be included directly."
+#endif
+
+#ifndef __SECRET_BACKEND_H__
+#define __SECRET_BACKEND_H__
+
+#include <glib-object.h>
+#include "secret-schema.h"
+#include "secret-service.h"
+#include "secret-value.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+        SECRET_BACKEND_NONE = SECRET_SERVICE_NONE,
+        SECRET_BACKEND_OPEN_SESSION = SECRET_SERVICE_OPEN_SESSION,
+        SECRET_BACKEND_LOAD_COLLECTIONS = SECRET_SERVICE_LOAD_COLLECTIONS,
+} SecretBackendFlags;
+
+#define SECRET_TYPE_BACKEND secret_backend_get_type ()
+G_DECLARE_INTERFACE (SecretBackend, secret_backend, SECRET, BACKEND, GObject)
+
+struct _SecretBackendInterface
+{
+        GTypeInterface parent_iface;
+
+        void         (*ensure_for_flags)        (SecretBackend *self,
+                                                 SecretBackendFlags flags,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+        gboolean     (*ensure_for_flags_finish) (SecretBackend *self,
+                                                 GAsyncResult *result,
+                                                 GError **error);
+
+        void         (*store)                   (SecretBackend *self,
+                                                 const SecretSchema *schema,
+                                                 GHashTable *attributes,
+                                                 const gchar *collection,
+                                                 const gchar *label,
+                                                 SecretValue *value,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+        gboolean     (*store_finish)            (SecretBackend *self,
+                                                 GAsyncResult *result,
+                                                 GError **error);
+
+        void         (*lookup)                  (SecretBackend *self,
+                                                 const SecretSchema *schema,
+                                                 GHashTable *attributes,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+        SecretValue *(*lookup_finish)           (SecretBackend *self,
+                                                 GAsyncResult *result,
+                                                 GError **error);
+
+        void         (*clear)                   (SecretBackend *self,
+                                                 const SecretSchema *schema,
+                                                 GHashTable *attributes,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+        gboolean     (*clear_finish)            (SecretBackend *self,
+                                                 GAsyncResult *result,
+                                                 GError **error);
+
+        void         (*search)                  (SecretBackend *self,
+                                                 const SecretSchema *schema,
+                                                 GHashTable *attributes,
+                                                 SecretSearchFlags flags,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+        GList *      (*search_finish)           (SecretBackend *self,
+                                                 GAsyncResult *result,
+                                                 GError **error);
+};
+
+#define SECRET_BACKEND_EXTENSION_POINT_NAME "secret-backend"
+
+void           _secret_backend_ensure_extension_point
+                                         (void);
+
+void           secret_backend_get        (SecretBackendFlags flags,
+                                          GCancellable *cancellable,
+                                          GAsyncReadyCallback callback,
+                                          gpointer user_data);
+
+SecretBackend *secret_backend_get_finish (GAsyncResult *result,
+                                          GError **error);
+
+G_END_DECLS
+
+#endif /* __SECRET_BACKEND_H__ */


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