From e6456698ec6c3ef00a3e8726bc78096a60d8fc35 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sun, 30 Jun 2019 05:52:01 +0200 Subject: [PATCH 1/7] secret-service: Move parent property setting to constructor This makes it possible to instantiate a SecretService instance directly through g_initable_new() or g_async_initable_new_async(). --- libsecret/secret-service.c | 71 ++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/libsecret/secret-service.c b/libsecret/secret-service.c index 6dea0d1..f99fd7e 100644 --- a/libsecret/secret-service.c +++ b/libsecret/secret-service.c @@ -509,6 +509,38 @@ secret_service_real_get_item_gtype (SecretService *self) return klass->item_gtype; } +static const gchar * +get_default_bus_name (void) +{ + const gchar *bus_name; + + bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME"); + if (bus_name == NULL) + bus_name = SECRET_SERVICE_BUS_NAME; + + return bus_name; +} + +static GObject * +secret_service_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; + + object = G_OBJECT_CLASS (secret_service_parent_class)-> + constructor (type, n_construct_properties, construct_properties); + g_object_set (object, + "g-flags", G_DBUS_PROXY_FLAGS_NONE, + "g-interface-info", _secret_gen_service_interface_info (), + "g-name", get_default_bus_name (), + "g-bus-type", G_BUS_TYPE_SESSION, + "g-object-path", SECRET_SERVICE_PATH, + "g-interface-name", SECRET_SERVICE_INTERFACE, + NULL); + return object; +} + static void secret_service_class_init (SecretServiceClass *klass) { @@ -519,6 +551,7 @@ secret_service_class_init (SecretServiceClass *klass) object_class->set_property = secret_service_set_property; object_class->dispose = secret_service_dispose; object_class->finalize = secret_service_finalize; + object_class->constructor = secret_service_constructor; proxy_class->g_properties_changed = secret_service_properties_changed; proxy_class->g_signal = secret_service_signal; @@ -745,18 +778,6 @@ secret_service_async_initable_iface (GAsyncInitableIface *iface) iface->init_finish = secret_service_async_initable_init_finish; } -static const gchar * -get_default_bus_name (void) -{ - const gchar *bus_name; - - bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME"); - if (bus_name == NULL) - bus_name = SECRET_SERVICE_BUS_NAME; - - return bus_name; -} - /** * secret_service_get: * @flags: flags for which service functionality to ensure is initialized @@ -788,13 +809,7 @@ secret_service_get (SecretServiceFlags flags, if (service == NULL) { g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT, cancellable, callback, user_data, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-interface-info", _secret_gen_service_interface_info (), - "g-name", get_default_bus_name (), - "g-bus-type", G_BUS_TYPE_SESSION, - "g-object-path", SECRET_SERVICE_PATH, - "g-interface-name", SECRET_SERVICE_INTERFACE, - "flags", flags, + "flags", flags, NULL); /* Just have to ensure that the service matches flags */ @@ -890,12 +905,6 @@ secret_service_get_sync (SecretServiceFlags flags, if (service == NULL) { service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-interface-info", _secret_gen_service_interface_info (), - "g-name", get_default_bus_name (), - "g-bus-type", G_BUS_TYPE_SESSION, - "g-object-path", SECRET_SERVICE_PATH, - "g-interface-name", SECRET_SERVICE_INTERFACE, "flags", flags, NULL); @@ -970,12 +979,6 @@ secret_service_open (GType service_gtype, g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT, cancellable, callback, user_data, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-interface-info", _secret_gen_service_interface_info (), - "g-name", service_bus_name, - "g-bus-type", G_BUS_TYPE_SESSION, - "g-object-path", SECRET_SERVICE_PATH, - "g-interface-name", SECRET_SERVICE_INTERFACE, "flags", flags, NULL); } @@ -1052,12 +1055,6 @@ secret_service_open_sync (GType service_gtype, service_bus_name = get_default_bus_name (); return g_initable_new (service_gtype, cancellable, error, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-interface-info", _secret_gen_service_interface_info (), - "g-name", service_bus_name, - "g-bus-type", G_BUS_TYPE_SESSION, - "g-object-path", SECRET_SERVICE_PATH, - "g-interface-name", SECRET_SERVICE_INTERFACE, "flags", flags, NULL); } From a0d10597eea7cee22eee07ab22ad1867f6cbbc38 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sat, 29 Jun 2019 16:56:03 +0200 Subject: [PATCH 2/7] 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. --- .../libsecret/libsecret-sections.txt | 14 + libsecret/Makefile.am | 2 + libsecret/Secret-1.metadata | 6 + libsecret/meson.build | 2 + libsecret/secret-backend.c | 277 ++++++++++++++++++ libsecret/secret-backend.h | 111 +++++++ 6 files changed, 412 insertions(+) create mode 100644 libsecret/secret-backend.c create mode 100644 libsecret/secret-backend.h 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 SecretGenPrompt +
+secret-backend +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 +
+
secret-version 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 f7077cd..7e3dcd3 100644 --- a/libsecret/meson.build +++ b/libsecret/meson.build @@ -2,6 +2,7 @@ installed_headers_subdir = 'libsecret-@0@'.format(api_version_major) / 'libsecre 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..cc0ea87 --- /dev/null +++ b/libsecret/secret-backend.c @@ -0,0 +1,277 @@ +/* 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. + * + * Since: 0.19.0 + */ + +/** + * 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. + * + * Since: 0.19.0 + */ + +/** + * 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. + * + * Since: 0.19.0 + */ + +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. + * + * Since: 0.19.0 + */ + 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. + * + * Since: 0.19.0 + */ +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(). + * + * Since: 0.19.0 + */ +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 can be included directly." +#endif + +#ifndef __SECRET_BACKEND_H__ +#define __SECRET_BACKEND_H__ + +#include +#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__ */ From 71a19a95aec406104d6231126d6178b1392551ff Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Sat, 29 Jun 2019 16:57:51 +0200 Subject: [PATCH 3/7] secret-service: Implement SecretBackendInterface --- libsecret/secret-backend.c | 5 +- libsecret/secret-service.c | 172 ++++++++++++++++++++++++++++++++++++- 2 files changed, 172 insertions(+), 5 deletions(-) diff --git a/libsecret/secret-backend.c b/libsecret/secret-backend.c index cc0ea87..2c26c7d 100644 --- a/libsecret/secret-backend.c +++ b/libsecret/secret-backend.c @@ -125,16 +125,19 @@ backend_get_instance (void) static GType backend_get_impl_type (void) { - const gchar *envvar = g_getenv ("SECRET_BACKEND"); + const gchar *envvar; const gchar *extension_name; GIOExtension *e; GIOExtensionPoint *ep; + envvar = g_getenv ("SECRET_BACKEND"); if (envvar == NULL || *envvar == '\0') extension_name = "service"; else extension_name = envvar; + g_type_ensure (secret_service_get_type ()); + 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) { diff --git a/libsecret/secret-service.c b/libsecret/secret-service.c index f99fd7e..95498a6 100644 --- a/libsecret/secret-service.c +++ b/libsecret/secret-service.c @@ -15,6 +15,7 @@ #include "config.h" +#include "secret-backend.h" #include "secret-collection.h" #include "secret-dbus-generated.h" #include "secret-item.h" @@ -135,14 +136,24 @@ static GInitableIface *secret_service_initable_parent_iface = NULL; static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL; +static SecretBackendInterface *secret_service_backend_parent_iface = NULL; + static void secret_service_initable_iface (GInitableIface *iface); static void secret_service_async_initable_iface (GAsyncInitableIface *iface); +static void secret_service_backend_iface (SecretBackendInterface *iface); + G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY, G_ADD_PRIVATE (SecretService) G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface); G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface); + G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_service_backend_iface); + _secret_backend_ensure_extension_point (); + g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME, + g_define_type_id, + "service", + 0) ); static SecretService * @@ -571,10 +582,7 @@ secret_service_class_init (SecretServiceClass *klass) * A set of flags describing which parts of the secret service have * been initialized. */ - g_object_class_install_property (object_class, PROP_FLAGS, - 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)); + g_object_class_override_property (object_class, PROP_FLAGS, "flags"); /** * SecretService:collections: @@ -778,6 +786,162 @@ secret_service_async_initable_iface (GAsyncInitableIface *iface) iface->init_finish = secret_service_async_initable_init_finish; } +static void +secret_service_real_ensure_for_flags (SecretBackend *self, + SecretBackendFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + InitClosure *closure; + + g_return_if_fail (SECRET_IS_SERVICE (self)); + + task = g_task_new (self, cancellable, callback, user_data); + closure = g_slice_new0 (InitClosure); + g_task_set_task_data (task, closure, init_closure_free); + service_ensure_for_flags_async (SECRET_SERVICE (self), flags, task); + g_object_unref (task); +} + +static gboolean +secret_service_real_ensure_for_flags_finish (SecretBackend *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + + if (!g_task_propagate_boolean (G_TASK (result), error)) { + _secret_util_strip_remote_error (error); + return FALSE; + } + + return TRUE; +} + +static void +secret_service_real_store (SecretBackend *self, + const SecretSchema *schema, + GHashTable *attributes, + const gchar *collection, + const gchar *label, + SecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + + secret_service_store (SECRET_SERVICE (self), schema, attributes, + collection, label, value, + cancellable, callback, user_data); +} + +static gboolean +secret_service_real_store_finish (SecretBackend *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + + return secret_service_store_finish (SECRET_SERVICE (self), + result, error); +} + +static void +secret_service_real_lookup (SecretBackend *self, + const SecretSchema *schema, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + + secret_service_lookup (SECRET_SERVICE (self), schema, attributes, + cancellable, callback, user_data); +} + +static SecretValue * +secret_service_real_lookup_finish (SecretBackend *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + + return secret_service_lookup_finish (SECRET_SERVICE (self), + result, error); +} + +static void +secret_service_real_clear (SecretBackend *self, + const SecretSchema *schema, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + + secret_service_clear (SECRET_SERVICE (self), schema, attributes, + cancellable, callback, user_data); +} + +static gboolean +secret_service_real_clear_finish (SecretBackend *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); + + return secret_service_clear_finish (SECRET_SERVICE (self), + result, error); +} + +static void +secret_service_real_search (SecretBackend *self, + const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (SECRET_IS_SERVICE (self)); + + secret_service_search (SECRET_SERVICE (self), schema, attributes, flags, + cancellable, callback, user_data); +} + +static GList * +secret_service_real_search_finish (SecretBackend *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + + return secret_service_search_finish (SECRET_SERVICE (self), + result, error); +} + +static void +secret_service_backend_iface (SecretBackendInterface *iface) +{ + secret_service_backend_parent_iface = g_type_interface_peek_parent (iface); + + iface->ensure_for_flags = secret_service_real_ensure_for_flags; + iface->ensure_for_flags_finish = secret_service_real_ensure_for_flags_finish; + iface->store = secret_service_real_store; + iface->store_finish = secret_service_real_store_finish; + iface->lookup = secret_service_real_lookup; + iface->lookup_finish = secret_service_real_lookup_finish; + iface->clear = secret_service_real_clear; + iface->clear_finish = secret_service_real_clear_finish; + iface->search = secret_service_real_search; + iface->search_finish = secret_service_real_search_finish; +} + /** * secret_service_get: * @flags: flags for which service functionality to ensure is initialized From b37d2b8d201e9c6095ead8310fa5b416b75682db Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 1 Jul 2019 17:29:10 +0200 Subject: [PATCH 4/7] secret-backend: Add a way to uncache singleton instance This is ugly, but necessary to handle instance uncaching in SecretBackend when the backend instance is gone. --- libsecret/secret-backend.c | 14 ++++++++++++++ libsecret/secret-backend.h | 2 ++ libsecret/secret-service.c | 2 ++ 3 files changed, 18 insertions(+) diff --git a/libsecret/secret-backend.c b/libsecret/secret-backend.c index 2c26c7d..a63b75c 100644 --- a/libsecret/secret-backend.c +++ b/libsecret/secret-backend.c @@ -122,6 +122,20 @@ backend_get_instance (void) return instance; } +void +_secret_backend_uncache_instance (void) +{ + SecretBackend *instance = NULL; + + G_LOCK (backend_instance); + instance = backend_instance; + backend_instance = NULL; + G_UNLOCK (backend_instance); + + if (instance != NULL) + g_object_unref (instance); +} + static GType backend_get_impl_type (void) { diff --git a/libsecret/secret-backend.h b/libsecret/secret-backend.h index 7dae506..3dadffa 100644 --- a/libsecret/secret-backend.h +++ b/libsecret/secret-backend.h @@ -97,6 +97,8 @@ struct _SecretBackendInterface void _secret_backend_ensure_extension_point (void); +void _secret_backend_uncache_instance + (void); void secret_backend_get (SecretBackendFlags flags, GCancellable *cancellable, diff --git a/libsecret/secret-service.c b/libsecret/secret-service.c index 95498a6..36d2feb 100644 --- a/libsecret/secret-service.c +++ b/libsecret/secret-service.c @@ -191,6 +191,8 @@ service_uncache_instance (SecretService *which) if (watch != 0) g_bus_unwatch_name (watch); + _secret_backend_uncache_instance (); + return matched; } From 49e6e0cf6099234dbee0a24885745adf1d910971 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 1 Jul 2019 15:51:33 +0200 Subject: [PATCH 5/7] secret-password: Port to SecretBackend interface --- libsecret/secret-password.c | 381 ++++++++++++++++++++++++++++++++++-- 1 file changed, 361 insertions(+), 20 deletions(-) diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index 632ed2d..dd21e74 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -18,6 +18,7 @@ #include "secret-password.h" #include "secret-private.h" #include "secret-retrievable.h" +#include "secret-backend.h" #include "secret-value.h" #include @@ -102,6 +103,77 @@ secret_password_store (const SecretSchema *schema, g_hash_table_unref (attributes); } +typedef struct { + const SecretSchema *schema; + GHashTable *attributes; + gchar *collection; + gchar *label; + SecretValue *value; +} StoreClosure; + +static void +store_closure_free (gpointer data) +{ + StoreClosure *store = data; + _secret_schema_unref_if_nonstatic (store->schema); + g_hash_table_unref (store->attributes); + g_free (store->collection); + g_free (store->label); + secret_value_unref (store->value); + g_slice_free (StoreClosure, store); +} + +static void +on_store (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + SecretBackend *backend = SECRET_BACKEND (source); + SecretBackendInterface *iface; + GError *error = NULL; + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->store_finish != NULL); + + if (!iface->store_finish (backend, result, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +on_store_backend (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + StoreClosure *store = g_task_get_task_data (task); + SecretBackend *backend; + SecretBackendInterface *iface; + GError *error = NULL; + + backend = secret_backend_get_finish (result, &error); + if (backend == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->store != NULL); + + iface->store (backend, store->schema, store->attributes, + store->collection, store->label, store->value, + g_task_get_cancellable (task), + on_store, + task); +} + /** * secret_password_storev: (rename-to secret_password_store) * @schema: (nullable): the schema for attributes @@ -136,7 +208,8 @@ secret_password_storev (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { - SecretValue *value; + StoreClosure *store; + GTask *task; g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); @@ -147,12 +220,18 @@ secret_password_storev (const SecretSchema *schema, if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; - value = secret_value_new (password, -1, "text/plain"); + task = g_task_new (NULL, cancellable, callback, user_data); + store = g_slice_new0 (StoreClosure); + store->schema = _secret_schema_ref_if_nonstatic (schema); + store->attributes = g_hash_table_ref (attributes); + store->collection = g_strdup (collection); + store->label = g_strdup (label); + store->value = secret_value_new (password, -1, "text/plain"); + g_task_set_task_data (task, store, store_closure_free); - secret_service_store (NULL, schema, attributes, collection, - label, value, cancellable, callback, user_data); - - secret_value_unref (value); + secret_backend_get (SECRET_BACKEND_OPEN_SESSION, + cancellable, + on_store_backend, task); } /** @@ -237,6 +316,9 @@ secret_password_storev_binary (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { + StoreClosure *store; + GTask *task; + g_return_if_fail (label != NULL); g_return_if_fail (value != NULL); g_return_if_fail (attributes != NULL); @@ -246,8 +328,18 @@ secret_password_storev_binary (const SecretSchema *schema, if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE)) return; - secret_service_store (NULL, schema, attributes, collection, - label, value, cancellable, callback, user_data); + task = g_task_new (NULL, cancellable, callback, user_data); + store = g_slice_new0 (StoreClosure); + store->schema = _secret_schema_ref_if_nonstatic (schema); + store->attributes = g_hash_table_ref (attributes); + store->collection = g_strdup (collection); + store->label = g_strdup (label); + store->value = secret_value_ref (value); + g_task_set_task_data (task, store, store_closure_free); + + secret_backend_get (SECRET_BACKEND_OPEN_SESSION, + cancellable, + on_store_backend, task); } /** @@ -264,7 +356,9 @@ secret_password_store_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return secret_service_store_finish (NULL, result, error); + g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); } /** @@ -556,6 +650,75 @@ secret_password_lookup (const SecretSchema *schema, g_hash_table_unref (attributes); } +typedef struct { + const SecretSchema *schema; + GHashTable *attributes; +} LookupClosure; + +static void +lookup_closure_free (gpointer data) +{ + LookupClosure *closure = data; + _secret_schema_unref_if_nonstatic (closure->schema); + g_hash_table_unref (closure->attributes); + g_slice_free (LookupClosure, closure); +} + +static void +on_lookup (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + SecretBackend *backend = SECRET_BACKEND (source); + SecretBackendInterface *iface; + SecretValue *value; + GError *error = NULL; + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->store_finish != NULL); + + value = iface->lookup_finish (backend, result, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (value) + g_task_return_pointer (task, value, secret_value_unref); + else + g_task_return_pointer (task, NULL, NULL); + g_object_unref (task); +} + +static void +on_lookup_backend (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + LookupClosure *lookup = g_task_get_task_data (task); + SecretBackend *backend; + SecretBackendInterface *iface; + GError *error = NULL; + + backend = secret_backend_get_finish (result, &error); + if (backend == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->store != NULL); + + iface->lookup (backend, lookup->schema, lookup->attributes, + g_task_get_cancellable (task), + on_lookup, + task); +} + /** * secret_password_lookupv: (rename-to secret_password_lookup) * @schema: (nullable): the schema for attributes @@ -579,6 +742,9 @@ secret_password_lookupv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { + LookupClosure *lookup; + GTask *task; + g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -586,8 +752,15 @@ secret_password_lookupv (const SecretSchema *schema, if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; - secret_service_lookup (NULL, schema, attributes, - cancellable, callback, user_data); + task = g_task_new (NULL, cancellable, callback, user_data); + lookup = g_slice_new0 (LookupClosure); + lookup->schema = _secret_schema_ref_if_nonstatic (schema); + lookup->attributes = g_hash_table_ref (attributes); + g_task_set_task_data (task, lookup, lookup_closure_free); + + secret_backend_get (SECRET_BACKEND_OPEN_SESSION, + cancellable, + on_lookup_backend, task); } /** @@ -607,8 +780,9 @@ secret_password_lookup_nonpageable_finish (GAsyncResult *result, SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); - value = secret_service_lookup_finish (NULL, result, error); + value = g_task_propagate_pointer (G_TASK (result), error); if (value == NULL) return NULL; @@ -632,8 +806,9 @@ secret_password_lookup_binary_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); - return secret_service_lookup_finish (NULL, result, error); + return g_task_propagate_pointer (G_TASK (result), error); } /** @@ -653,8 +828,9 @@ secret_password_lookup_finish (GAsyncResult *result, SecretValue *value; g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); - value = secret_service_lookup_finish (NULL, result, error); + value = g_task_propagate_pointer (G_TASK (result), error); if (value == NULL) return NULL; @@ -1018,6 +1194,72 @@ secret_password_clear (const SecretSchema *schema, g_hash_table_unref (attributes); } +typedef struct { + const SecretSchema *schema; + GHashTable *attributes; +} ClearClosure; + +static void +clear_closure_free (gpointer data) +{ + ClearClosure *closure = data; + _secret_schema_unref_if_nonstatic (closure->schema); + g_hash_table_unref (closure->attributes); + g_slice_free (ClearClosure, closure); +} + +static void +on_clear (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + SecretBackend *backend = SECRET_BACKEND (source); + SecretBackendInterface *iface; + GError *error = NULL; + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->clear_finish != NULL); + + if (!iface->clear_finish (backend, result, &error)) { + if (error) + g_task_return_error (task, error); + else + g_task_return_boolean (task, FALSE); + g_object_unref (task); + return; + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +on_clear_backend (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + ClearClosure *clear = g_task_get_task_data (task); + SecretBackend *backend; + SecretBackendInterface *iface; + GError *error = NULL; + + backend = secret_backend_get_finish (result, &error); + if (backend == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->clear != NULL); + + iface->clear (backend, clear->schema, clear->attributes, + g_task_get_cancellable (task), + on_clear, + task); +} /** * secret_password_clearv: (rename-to secret_password_clear) @@ -1042,6 +1284,9 @@ secret_password_clearv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { + ClearClosure *clear; + GTask *task; + g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1049,8 +1294,15 @@ secret_password_clearv (const SecretSchema *schema, if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; - secret_service_clear (NULL, schema, attributes, - cancellable, callback, user_data); + task = g_task_new (NULL, cancellable, callback, user_data); + clear = g_slice_new0 (ClearClosure); + clear->schema = _secret_schema_ref_if_nonstatic (schema); + clear->attributes = g_hash_table_ref (attributes); + g_task_set_task_data (task, clear, clear_closure_free); + + secret_backend_get (SECRET_SERVICE_NONE, + cancellable, + on_clear_backend, task); } /** @@ -1068,7 +1320,9 @@ secret_password_clear_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return secret_service_clear_finish (NULL, result, error); + g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); } /** @@ -1221,6 +1475,81 @@ secret_password_search (const SecretSchema *schema, g_hash_table_unref (attributes); } +typedef struct { + const SecretSchema *schema; + GHashTable *attributes; + SecretSearchFlags flags; +} SearchClosure; + +static void +search_closure_free (gpointer data) +{ + SearchClosure *closure = data; + _secret_schema_unref_if_nonstatic (closure->schema); + g_hash_table_unref (closure->attributes); + g_slice_free (SearchClosure, closure); +} + +static void +object_list_free (gpointer data) +{ + GList *list = data; + g_list_free_full (list, g_object_unref); +} + +static void +on_search (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + SecretBackend *backend = SECRET_BACKEND (source); + SecretBackendInterface *iface; + GError *error = NULL; + GList *items; + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->search_finish != NULL); + + items = iface->search_finish (backend, result, &error); + if (error) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_task_return_pointer (task, items, object_list_free); + g_object_unref (task); +} + +static void +on_search_backend (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + SearchClosure *search = g_task_get_task_data (task); + SecretBackend *backend; + SecretBackendInterface *iface; + GError *error = NULL; + + backend = secret_backend_get_finish (result, &error); + if (backend == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + iface = SECRET_BACKEND_GET_IFACE (backend); + g_return_if_fail (iface->search != NULL); + + iface->search (backend, + search->schema, search->attributes, search->flags, + g_task_get_cancellable (task), + on_search, + task); +} + /** * secret_password_searchv: (rename-to secret_password_search) * @schema: (nullable): the schema for attributes @@ -1246,6 +1575,9 @@ secret_password_searchv (const SecretSchema *schema, GAsyncReadyCallback callback, gpointer user_data) { + SearchClosure *search; + GTask *task; + g_return_if_fail (attributes != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); @@ -1253,8 +1585,16 @@ secret_password_searchv (const SecretSchema *schema, if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) return; - secret_service_search (NULL, schema, attributes, flags, - cancellable, callback, user_data); + task = g_task_new (NULL, cancellable, callback, user_data); + search = g_slice_new0 (SearchClosure); + search->schema = _secret_schema_ref_if_nonstatic (schema); + search->attributes = g_hash_table_ref (attributes); + search->flags = flags; + g_task_set_task_data (task, search, search_closure_free); + + secret_backend_get (SECRET_SERVICE_NONE, + cancellable, + on_search_backend, task); } /** @@ -1274,8 +1614,9 @@ secret_password_search_finish (GAsyncResult *result, GError **error) { g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); - return secret_service_search_finish (NULL, result, error); + return g_task_propagate_pointer (G_TASK (result), error); } /** From 060061905ac4ede1ceeef1a0af86cb47aacd28d3 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 19 Aug 2019 07:22:55 +0200 Subject: [PATCH 6/7] secret-password: Add necessary gir annotations --- libsecret/secret-password.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index dd21e74..491e211 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -177,12 +177,12 @@ on_store_backend (GObject *source, /** * secret_password_storev: (rename-to secret_password_store) * @schema: (nullable): the schema for attributes - * @attributes: (element-type utf8 utf8): the attribute keys and values + * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret * @label: label for the secret * @password: the null-terminated password to store * @cancellable: optional cancellation object - * @callback: called when the operation completes + * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Store a password in the secret service. @@ -289,12 +289,12 @@ secret_password_store_binary (const SecretSchema *schema, /** * secret_password_storev_binary: (rename-to secret_password_store_binary) * @schema: (nullable): the schema for attributes - * @attributes: (element-type utf8 utf8): the attribute keys and values + * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @collection: (allow-none): a collection alias, or D-Bus object path of the collection where to store the secret * @label: label for the secret * @value: a #SecretValue * @cancellable: optional cancellation object - * @callback: called when the operation completes + * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Store a password in the secret service. @@ -722,9 +722,9 @@ on_lookup_backend (GObject *source, /** * secret_password_lookupv: (rename-to secret_password_lookup) * @schema: (nullable): the schema for attributes - * @attributes: (element-type utf8 utf8): the attribute keys and values + * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @cancellable: optional cancellation object - * @callback: called when the operation completes + * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Lookup a password in the secret service. @@ -1264,9 +1264,9 @@ on_clear_backend (GObject *source, /** * secret_password_clearv: (rename-to secret_password_clear) * @schema: (nullable): the schema for the attributes - * @attributes: (element-type utf8 utf8): the attribute keys and values + * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @cancellable: optional cancellation object - * @callback: called when the operation completes + * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Remove unlocked matching passwords from the secret service. @@ -1553,10 +1553,10 @@ on_search_backend (GObject *source, /** * secret_password_searchv: (rename-to secret_password_search) * @schema: (nullable): the schema for attributes - * @attributes: (element-type utf8 utf8): the attribute keys and values + * @attributes: (element-type utf8 utf8) (transfer full): the attribute keys and values * @flags: search option flags * @cancellable: optional cancellation object - * @callback: called when the operation completes + * @callback: (scope async): called when the operation completes * @user_data: data to be passed to the callback * * Search for items in the secret service. From a6317352e8357b44d36e53cba80dedfd69a30630 Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Mon, 7 Oct 2019 12:43:43 +0200 Subject: [PATCH 7/7] build: Properly expose backend vfuncs to vapi --- libsecret/Secret-1.metadata | 8 ++++---- libsecret/meson.build | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libsecret/Secret-1.metadata b/libsecret/Secret-1.metadata index 3f01645..8288950 100644 --- a/libsecret/Secret-1.metadata +++ b/libsecret/Secret-1.metadata @@ -68,7 +68,7 @@ Service .prompt_at_dbus_path_finish skip=false nullable=true Backend - .store skip=true - .lookup skip=true - .clear skip=true - .search skip=true + .search_finish skip=false type="GLib.List" + .*#virtual_method.schema nullable + .*#virtual_method.attributes type="GLib.HashTable" + .*#virtual_method.collection nullable diff --git a/libsecret/meson.build b/libsecret/meson.build index 7e3dcd3..0421ac9 100644 --- a/libsecret/meson.build +++ b/libsecret/meson.build @@ -98,6 +98,8 @@ libsecret_dep = declare_dependency( libsecret_gir_sources = [ 'secret-attributes.c', 'secret-attributes.h', + 'secret-backend.c', + 'secret-backend.h', 'secret-collection.c', 'secret-collection.h', 'secret-item.c',