summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2012-01-11 07:44:32 +0100
committerStef Walter <stefw@collabora.co.uk>2012-01-13 14:45:55 +0100
commitf2e275f25eebd5456967d431580668fcbbcf0601 (patch)
tree75a156a418afd020689f40352c2e7e92d3b3463d
parentb36268afc1f5c2b1bcae605d39da8afc4be49bab (diff)
downloadlibsecret-f2e275f25eebd5456967d431580668fcbbcf0601.tar.gz
Prompting and item deletion
-rw-r--r--build/glib.supp8
-rw-r--r--build/unknown.supp25
-rw-r--r--egg/egg-testing.c11
-rw-r--r--egg/egg-testing.h2
-rw-r--r--library/Makefile.am2
-rw-r--r--library/gsecret-collection.h1
-rw-r--r--library/gsecret-item.c75
-rw-r--r--library/gsecret-item.h2
-rw-r--r--library/gsecret-password.c440
-rw-r--r--library/gsecret-password.h87
-rw-r--r--library/gsecret-private.h24
-rw-r--r--library/gsecret-prompt.c433
-rw-r--r--library/gsecret-prompt.h35
-rw-r--r--library/gsecret-service.c710
-rw-r--r--library/gsecret-service.h145
-rw-r--r--library/gsecret-types.h30
-rw-r--r--library/gsecret-util.c75
-rw-r--r--library/gsecret-value.h4
-rw-r--r--library/org.freedesktop.Secrets.xml142
-rw-r--r--library/tests/Makefile.am2
-rw-r--r--library/tests/mock-service-delete.py17
-rw-r--r--library/tests/mock-service-prompt.py42
-rw-r--r--library/tests/mock/service.py72
-rw-r--r--library/tests/test-password.c137
-rw-r--r--library/tests/test-prompt.c429
-rw-r--r--library/tests/test-service.c214
-rw-r--r--library/tests/test-session.c4
27 files changed, 2982 insertions, 186 deletions
diff --git a/build/glib.supp b/build/glib.supp
index 2da79f1..e62121d 100644
--- a/build/glib.supp
+++ b/build/glib.supp
@@ -317,3 +317,11 @@
fun:g_hash_table_remove
fun:g_variant_type_info_unref
}
+{
+ g_rw_lock_reader_lock
+ Memcheck:Leak
+ ...
+ fun:g_rw_lock_impl_new
+ fun:g_rw_lock_get_impl
+ fun:g_rw_lock_reader_lock
+}
diff --git a/build/unknown.supp b/build/unknown.supp
index b57beb3..6938016 100644
--- a/build/unknown.supp
+++ b/build/unknown.supp
@@ -364,3 +364,28 @@
fun:g_main_loop_run
fun:gdbus_shared_thread_func
}
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ ...
+ fun:g_source_new
+ fun:g_idle_source_new
+ fun:call_destroy_notify
+ fun:g_dbus_connection_signal_unsubscribe
+}
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ ...
+ fun:g_source_set_callback
+ fun:call_destroy_notify
+ fun:g_dbus_connection_signal_unsubscribe
+}
+{
+ <insert_a_suppression_name_here>
+ Memcheck:Leak
+ ...
+ fun:g_malloc0_n
+ fun:call_destroy_notify
+ fun:g_dbus_connection_signal_unsubscribe
+}
diff --git a/egg/egg-testing.c b/egg/egg-testing.c
index 0fed4a1..7fa2a60 100644
--- a/egg/egg-testing.c
+++ b/egg/egg-testing.c
@@ -114,6 +114,17 @@ egg_test_wait_until (int timeout)
return (wait_until_impl) (timeout);
}
+void
+egg_test_wait_idle (void)
+{
+ GMainContext *context;
+
+ g_assert (wait_until_impl != NULL);
+
+ context = g_main_context_get_thread_default ();
+ while (g_main_context_iteration (context, FALSE));
+}
+
static GMainLoop *wait_loop = NULL;
static void
diff --git a/egg/egg-testing.h b/egg/egg-testing.h
index 7ac3149..3ed8081 100644
--- a/egg/egg-testing.h
+++ b/egg/egg-testing.h
@@ -59,6 +59,8 @@ void egg_test_wait_stop (void);
gboolean egg_test_wait_until (int timeout);
+void egg_test_wait_idle (void);
+
gint egg_tests_run_with_loop (void);
#endif /* EGG_DH_H_ */
diff --git a/library/Makefile.am b/library/Makefile.am
index 44c872f..09ca8e9 100644
--- a/library/Makefile.am
+++ b/library/Makefile.am
@@ -17,6 +17,8 @@ BUILT_SOURCES = \
libgsecret_la_SOURCES = \
gsecret-value.h gsecret-value.c \
gsecret-item.h gsecret-item.c \
+ gsecret-password.h gsecret-password.c \
+ gsecret-prompt.h gsecret-prompt.c \
gsecret-service.h gsecret-service.c \
gsecret-util.c \
$(BUILT_SOURCES) \
diff --git a/library/gsecret-collection.h b/library/gsecret-collection.h
index 61f03a5..341618b 100644
--- a/library/gsecret-collection.h
+++ b/library/gsecret-collection.h
@@ -24,7 +24,6 @@ G_BEGIN_DECLS
#define GSECRET_IS_SERVICE_CLASS(class) (GSECRET_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_SERVICE))
#define GSECRET_SERVICE_GET_CLASS(inst) (GSECRET_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_SERVICE, GSecretServiceClass))
-typedef struct _GSecretService GSecretService;
typedef struct _GSecretServiceClass GSecretServiceClass;
typedef struct _GSecretServicePrivate GSecretServicePrivate;
diff --git a/library/gsecret-item.c b/library/gsecret-item.c
index 0318bff..1408b53 100644
--- a/library/gsecret-item.c
+++ b/library/gsecret-item.c
@@ -38,96 +38,47 @@ gsecret_item_class_init (GSecretItemClass *klass)
}
-static void
-on_item_delete_ready (GObject *source, GAsyncResult *result, gpointer user_data)
-{
- GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
- GError *error = NULL;
- GVariant *ret;
-
- ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
- result, &error);
- if (ret == NULL)
- g_simple_async_result_take_error (res, error);
- else
- g_variant_unref (ret);
-
- g_simple_async_result_complete (res);
- g_object_unref (res);
-}
-
void
-gsecret_item_delete (GSecretItem *self, GCancellable *cancellable,
- GAsyncReadyCallback callback, gpointer user_data)
+gsecret_item_delete (GSecretItem *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
const gchar *object_path;
- gchar *collection_path;
- GSimpleAsyncResult *res;
g_return_if_fail (GSECRET_IS_ITEM (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- res = g_simple_async_result_new (G_OBJECT (self), callback,
- user_data, gsecret_item_delete);
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
- collection_path = _gsecret_util_parent_path (object_path);
-
- g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)),
- g_dbus_proxy_get_name (G_DBUS_PROXY (self)),
- collection_path, GSECRET_COLLECTION_INTERFACE,
- "Delete", NULL, NULL,
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
- cancellable, on_item_delete_ready, res);
-
- g_free (collection_path);
+ gsecret_service_delete_path (self->pv->service, object_path,
+ cancellable, callback, user_data);
}
gboolean
-gsecret_item_delete_finish (GSecretItem *self, GAsyncResult *result,
+gsecret_item_delete_finish (GSecretItem *self,
+ GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (g_simple_async_result_is_valid (result,
- G_OBJECT (self), gsecret_item_delete), FALSE);
-
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
- error))
- return FALSE;
- return TRUE;
+ return gsecret_service_delete_path_finish (self->pv->service, result, error);
}
gboolean
-gsecret_item_delete_sync (GSecretItem *self, GCancellable *cancellable,
+gsecret_item_delete_sync (GSecretItem *self,
+ GCancellable *cancellable,
GError **error)
{
const gchar *object_path;
- gchar *collection_path;
- GVariant *ret;
g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
- collection_path = _gsecret_util_parent_path (object_path);
-
- ret = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)),
- g_dbus_proxy_get_name (G_DBUS_PROXY (self)),
- collection_path, GSECRET_COLLECTION_INTERFACE,
- "Delete", NULL, NULL,
- G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
- cancellable, error);
-
- g_free (collection_path);
-
- if (ret != NULL) {
- g_variant_unref (ret);
- return TRUE;
- }
-
- return FALSE;
+ return gsecret_service_delete_path_sync (self->pv->service,
+ object_path, cancellable, error);
}
static void
diff --git a/library/gsecret-item.h b/library/gsecret-item.h
index 8ec1e00..b29c29e 100644
--- a/library/gsecret-item.h
+++ b/library/gsecret-item.h
@@ -16,6 +16,7 @@
#include <gio/gio.h>
#include "gsecret-item.h"
+#include "gsecret-service.h"
#include "gsecret-value.h"
G_BEGIN_DECLS
@@ -27,7 +28,6 @@ G_BEGIN_DECLS
#define GSECRET_IS_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_ITEM))
#define GSECRET_ITEM_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_ITEM, GSecretItemClass))
-typedef struct _GSecretItem GSecretItem;
typedef struct _GSecretItemClass GSecretItemClass;
typedef struct _GSecretItemPrivate GSecretItemPrivate;
diff --git a/library/gsecret-password.c b/library/gsecret-password.c
new file mode 100644
index 0000000..d504461
--- /dev/null
+++ b/library/gsecret-password.c
@@ -0,0 +1,440 @@
+/* GSecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2011 Collabora Ltd.
+ *
+ * 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "config.h"
+
+#include "gsecret-password.h"
+#include "gsecret-private.h"
+#include "gsecret-value.h"
+
+#include <egg/egg-secure-memory.h>
+
+typedef struct {
+ GAsyncResult *result;
+ GMainContext *context;
+ GMainLoop *loop;
+} SyncClosure;
+
+static SyncClosure *
+sync_closure_new (void)
+{
+ SyncClosure *closure;
+
+ closure = g_new0 (SyncClosure, 1);
+
+ closure->context = g_main_context_new ();
+ closure->loop = g_main_loop_new (closure->context, FALSE);
+
+ return closure;
+}
+
+static void
+sync_closure_free (gpointer data)
+{
+ SyncClosure *closure = data;
+
+ g_clear_object (&closure->result);
+ g_main_loop_unref (closure->loop);
+ g_main_context_unref (closure->context);
+}
+
+static void
+on_sync_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SyncClosure *closure = user_data;
+ closure->result = g_object_ref (result);
+ g_main_loop_quit (closure->loop);
+}
+
+#if 0
+
+typedef struct {
+ GVariant *properties;
+ gchar *collection_path;
+ GSecretValue *secret;
+ GCancellable *cancellable;
+} StoreClosure;
+
+static void
+store_closure_free (gpointer data)
+{
+ StoreClosure *closure = data;
+ g_variant_unref (closure->properties);
+ g_free (closure->collection_path);
+ gsecret_value_unref (closure->secret);
+ g_clear_object (closure->cancellable);
+ g_free (closure);
+}
+
+static void
+on_create_item_reply (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+
+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+ if (error == NULL) {
+ g_variant_get (retval, "(&o&o)", &item_path, &prompt_path);
+ if (prompt_path xxx)
+ gsecret_prompt_perform (self, "", closure->cancellable,
+ on_store_prompt_complete, NULL);
+
+ if (g_strcmp0 (item_path, "/") != 0)
+ xxx complete!
+ }
+
+ g_object_unref (res);
+}
+
+static void
+on_store_service_connected (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretService *service;
+ GError *error = NULL;
+ GDBusProxy *proxy;
+ GVariant *params;
+
+ service = _gsecret_service_bare_connect_finish (result, &error);
+ if (error == NULL) {
+ params = g_variant_new ("(&a{sv}&(oayays)b)",
+ closure->properties,
+ _gsecret_service_encode_secret (service, closure->secret),
+ TRUE);
+
+ proxy = G_DBUS_PROXY (service);
+ g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
+ g_dbus_proxy_get_name (proxy),
+ closure->collection_path,
+ GSECRET_COLLECTION_INTERFACE,
+ "CreateItem", params, G_VARIANT_TYPE ("(oo)"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
+ closure->cancellable, on_create_item_reply,
+ g_object_ref (res));
+ } else {
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+
+ <arg name="item" type="o" direction="out"/>
+ <arg name="prompt" type="o" direction="out"/>
+ }
+
+ g_object_unref (res);
+}
+
+void
+gsecret_password_store (const GSecretSchema *schema,
+ const gchar *collection_path,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+ GSimpleAsyncResult *res;
+ GVariant *attributes;
+ StoreClosure *closure;
+ GVariantBuilder builder;
+ va_list va;
+
+ g_return_if_fail (schema != NULL);
+ g_return_if_fail (label != NULL);
+ g_return_if_fail (password != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ /* Build up the attributes */
+ va_start (va, user_data);
+ attributes = build_attributes (schema, va);
+ va_end (va);
+ g_return_if_fail (attributes != NULL);
+
+ /* Build up the various properties */
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Attributes", attributes);
+ g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Label", g_variant_new_string ("label"));
+ g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Schema", g_variant_new_string (schema->schema_name));
+
+ res = g_simple_async_result_new (NULL, callback, user_data,
+ gsecret_password_store_finish);
+ closure = g_new0 (StoreClosure, 1);
+ closure->properties = g_variant_ref_sink (g_variant_builder_end (&builder));
+ closure->collection_path = g_strdup (collection_path);
+ closure->secret = gsecret_value_new (password, -1, "text/plain");
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free);
+
+ _gsecret_service_bare_connect_with_session (cancellable, on_store_service_connected,
+ g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+#if 0
+gboolean
+gsecret_password_store_finish (GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+}
+
+gboolean
+gsecret_password_store_sync (const GSecretPasswordSchema *schema,
+ const gchar *collection,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GError **error,
+ const gchar *attribute_name,
+ ...)
+{
+ g_return_val_if_fail (schema != NULL, FALSE);
+ g_return_val_if_fail (display_name != NULL, FALSE);
+ g_return_val_if_fail (password != NULL, FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+}
+
+void
+gsecret_password_lookup (const GSecretPasswordSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ const gchar *attribute_name,
+ ...)
+{
+ g_return_if_fail (schema != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+}
+
+gchar *
+gsecret_password_lookup_finish (GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+}
+
+gchar *
+gsecret_password_lookup_sync (const GSecretPasswordSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ const gchar *attribute_name,
+ ...)
+{
+ g_return_val_if_fail (schema != NULL, NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+}
+
+#endif
+#endif
+
+typedef struct {
+ GCancellable *cancellable;
+ GHashTable *attributes;
+ gboolean deleted;
+} DeleteClosure;
+
+static void
+delete_closure_free (gpointer data)
+{
+ DeleteClosure *closure = data;
+ g_clear_object (&closure->cancellable);
+ g_hash_table_unref (closure->attributes);
+ g_slice_free (DeleteClosure, closure);
+}
+
+void
+gsecret_password_delete (const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+ GHashTable *attributes;
+ va_list va;
+
+ g_return_if_fail (schema != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ va_start (va, user_data);
+ attributes = _gsecret_util_attributes_for_varargs (schema, va);
+ va_end (va);
+
+ gsecret_password_deletev (attributes, cancellable,
+ callback, user_data);
+
+ g_hash_table_unref (attributes);
+}
+
+static void
+on_delete_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GError *error = NULL;
+
+ closure->deleted = gsecret_service_delete_password_finish (GSECRET_SERVICE (source),
+ result, &error);
+ if (error != NULL)
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+
+ g_object_unref (res);
+}
+
+static void
+on_delete_connect (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretService *service;
+ GError *error = NULL;
+
+ service = _gsecret_service_bare_connect_finish (result, &error);
+ if (error == NULL) {
+ gsecret_service_delete_passwordv (service, closure->attributes,
+ closure->cancellable, on_delete_complete,
+ g_object_ref (res));
+ g_object_unref (service);
+
+ } else {
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+ }
+
+ g_object_unref (res);
+}
+
+void
+gsecret_password_deletev (GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ DeleteClosure *closure;
+
+ g_return_if_fail (attributes != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ res = g_simple_async_result_new (NULL, callback, user_data,
+ gsecret_password_deletev);
+ closure = g_slice_new0 (DeleteClosure);
+ closure->attributes = g_hash_table_ref (attributes);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
+
+ _gsecret_service_bare_connect (NULL, FALSE, cancellable,
+ on_delete_connect,
+ g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+gboolean
+gsecret_password_delete_finish (GAsyncResult *result,
+ GError **error)
+{
+ DeleteClosure *closure;
+ GSimpleAsyncResult *res;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+ gsecret_password_deletev), FALSE);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ return closure->deleted;
+}
+
+gboolean
+gsecret_password_delete_sync (const GSecretSchema* schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+ GHashTable *attributes;
+ gboolean result;
+ va_list va;
+
+ g_return_val_if_fail (schema != NULL, FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ va_start (va, error);
+ attributes = _gsecret_util_attributes_for_varargs (schema, va);
+ va_end (va);
+
+ result = gsecret_password_deletev_sync (attributes, cancellable, error);
+
+ g_hash_table_unref (attributes);
+
+ return result;
+}
+
+gboolean
+gsecret_password_deletev_sync (GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SyncClosure *closure;
+ gboolean result;
+
+ g_return_val_if_fail (attributes != NULL, FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ closure = sync_closure_new ();
+ g_main_context_push_thread_default (closure->context);
+
+ gsecret_password_deletev (attributes, cancellable,
+ on_sync_result, closure);
+
+ g_main_loop_run (closure->loop);
+
+ result = gsecret_password_delete_finish (closure->result, error);
+
+ g_main_context_pop_thread_default (closure->context);
+ sync_closure_free (closure);
+
+ return result;
+}
+
+void
+gsecret_password_free (gpointer password)
+{
+ if (password == NULL)
+ return;
+
+ egg_secure_strfree (password);
+}
+
diff --git a/library/gsecret-password.h b/library/gsecret-password.h
new file mode 100644
index 0000000..9ab2250
--- /dev/null
+++ b/library/gsecret-password.h
@@ -0,0 +1,87 @@
+/* GSecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2011 Collabora Ltd.
+ *
+ * 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#ifndef __GSECRET_PASSWORD_H__
+#define __GSECRET_PASSWORD_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#include "gsecret-types.h"
+
+#if 0
+
+void gsecret_password_store (const GSecretSchema *schema,
+ const gchar *collection_path,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gsecret_password_store_finish (GAsyncResult *result,
+ GError **error);
+
+void gsecret_password_store_sync (const GSecretSchema *schema,
+ const gchar *collection,
+ const gchar *display_name,
+ const gchar *password,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gsecret_password_lookup (const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar * gsecret_password_lookup_finish (GAsyncResult *result,
+ GError **error);
+
+gchar * gsecret_password_lookup_sync (const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+#endif
+
+void gsecret_password_delete (const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gsecret_password_deletev (GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gsecret_password_delete_finish (GAsyncResult *result,
+ GError **error);
+
+gboolean gsecret_password_delete_sync (const GSecretSchema* schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gsecret_password_deletev_sync (GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error);
+
+void gsecret_password_free (gpointer password);
+
+G_END_DECLS
+
+#endif /* __G_SERVICE_H___ */
diff --git a/library/gsecret-private.h b/library/gsecret-private.h
index 17c97c9..15b0b6b 100644
--- a/library/gsecret-private.h
+++ b/library/gsecret-private.h
@@ -30,22 +30,44 @@ typedef struct {
#define GSECRET_SERVICE_BUS_NAME "org.freedesktop.Secret.Service"
+#define GSECRET_ITEM_INTERFACE "org.freedesktop.Secret.Item"
+#define GSECRET_COLLECTION_INTERFACE "org.freedesktop.Secret.Collection"
+#define GSECRET_PROMPT_INTERFACE "org.freedesktop.Secret.Prompt"
#define GSECRET_SERVICE_INTERFACE "org.freedesktop.Secret.Service"
-#define GSECRET_COLLECTION_INTERFACE "org.freedesktop.Secret.Collection"
+#define GSECRET_PROMPT_SIGNAL_COMPLETED "Completed"
GSecretParams * _gsecret_params_new (GCancellable *cancellable,
GVariant *in);
void _gsecret_params_free (gpointer data);
+GSecretPrompt * _gsecret_prompt_instance (GDBusConnection *connection,
+ const gchar *object_path);
+
gchar * _gsecret_util_parent_path (const gchar *path);
+gboolean _gsecret_util_empty_path (const gchar *path);
+
GVariant * _gsecret_util_variant_for_attributes (GHashTable *attributes);
+GHashTable * _gsecret_util_attributes_for_varargs (const GSecretSchema *schema,
+ va_list va);
+
+void _gsecret_service_set_default_bus_name (const gchar *bus_name);
+
GSecretService * _gsecret_service_bare_instance (GDBusConnection *connection,
const gchar *bus_name);
+void _gsecret_service_bare_connect (const gchar *bus_name,
+ gboolean ensure_session,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GSecretService * _gsecret_service_bare_connect_finish (GAsyncResult *result,
+ GError **error);
+
GVariant * _gsecret_service_encode_secret (GSecretService *self,
GSecretValue *value);
diff --git a/library/gsecret-prompt.c b/library/gsecret-prompt.c
new file mode 100644
index 0000000..f1e34c6
--- /dev/null
+++ b/library/gsecret-prompt.c
@@ -0,0 +1,433 @@
+/* GSecret - GLib wrapper for Secret Prompt
+ *
+ * Copyright 2011 Collabora Ltd.
+ *
+ * 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+#include "config.h"
+
+#include "gsecret-dbus-generated.h"
+#include "gsecret-private.h"
+#include "gsecret-prompt.h"
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gcrypt.h>
+
+struct _GSecretPromptPrivate {
+ gint prompted;
+ GVariant *last_result;
+};
+
+G_DEFINE_TYPE (GSecretPrompt, gsecret_prompt, G_TYPE_DBUS_PROXY);
+
+static void
+gsecret_prompt_init (GSecretPrompt *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSECRET_TYPE_PROMPT,
+ GSecretPromptPrivate);
+}
+
+static void
+gsecret_prompt_finalize (GObject *obj)
+{
+ GSecretPrompt *self = GSECRET_PROMPT (obj);
+
+ if (self->pv->last_result)
+ g_variant_unref (self->pv->last_result);
+
+ G_OBJECT_CLASS (gsecret_prompt_parent_class)->finalize (obj);
+}
+
+static void
+gsecret_prompt_class_init (GSecretPromptClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gsecret_prompt_finalize;
+
+ g_type_class_add_private (klass, sizeof (GSecretPromptPrivate));
+}
+
+typedef struct {
+ GMainLoop *loop;
+ GAsyncResult *result;
+} RunClosure;
+
+static void
+on_prompt_run_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ RunClosure *closure = user_data;
+ closure->result = g_object_ref (result);
+ g_main_loop_quit (closure->loop);
+}
+
+GSecretPrompt *
+gsecret_prompt_instance (GSecretService *service,
+ const gchar *prompt_path)
+{
+ GDBusProxy *proxy;
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (service), NULL);
+ g_return_val_if_fail (prompt_path != NULL, NULL);
+
+ proxy = G_DBUS_PROXY (service);
+ prompt = g_initable_new (GSECRET_TYPE_PROMPT, NULL, &error,
+ "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ "g-interface-info", _gsecret_gen_prompt_interface_info (),
+ "g-name", g_dbus_proxy_get_name (proxy),
+ "g-connection", g_dbus_proxy_get_connection (proxy),
+ "g-object-path", prompt_path,
+ "g-interface-name", GSECRET_PROMPT_INTERFACE,
+ NULL);
+
+ if (error != NULL) {
+ g_warning ("couldn't create GSecretPrompt object: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ return prompt;
+}
+
+gboolean
+gsecret_prompt_run (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GMainContext *context;
+ RunClosure *closure;
+ gboolean ret;
+
+ g_return_val_if_fail (GSECRET_IS_PROMPT (self), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ context = g_main_context_get_thread_default ();
+
+ closure = g_new0 (RunClosure, 1);
+ closure->loop = g_main_loop_new (context, FALSE);
+
+ gsecret_prompt_perform (self, window_id, cancellable,
+ on_prompt_run_complete, closure);
+
+ g_main_loop_run (closure->loop);
+
+ ret = gsecret_prompt_perform_finish (self, closure->result, error);
+
+ g_main_loop_unref (closure->loop);
+ g_object_unref (closure->result);
+ g_free (closure);
+
+ return ret;
+}
+
+gboolean
+gsecret_prompt_perform_sync (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GMainContext *context;
+ gboolean ret;
+
+ g_return_val_if_fail (GSECRET_IS_PROMPT (self), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ context = g_main_context_new ();
+ g_main_context_push_thread_default (context);
+
+ ret = gsecret_prompt_run (self, window_id, cancellable, error);
+
+ /* Needed to prevent memory leaks */
+ while (g_main_context_iteration (context, FALSE));
+
+ g_main_context_pop_thread_default (context);
+ g_main_context_unref (context);
+
+ return ret;
+}
+
+typedef struct {
+ GDBusConnection *connection;
+ GCancellable *call_cancellable;
+ GCancellable *async_cancellable;
+ gulong cancelled_sig;
+ gboolean prompting;
+ gboolean dismissed;
+ gboolean vanished;
+ gboolean completed;
+ guint signal;
+ guint watch;
+} PerformClosure;
+
+static void
+perform_closure_free (gpointer data)
+{
+ PerformClosure *closure = data;
+ g_object_unref (closure->call_cancellable);
+ g_clear_object (&closure->async_cancellable);
+ g_object_unref (closure->connection);
+ g_assert (closure->signal == 0);
+ g_assert (closure->watch == 0);
+ g_slice_free (PerformClosure, closure);
+}
+
+static void
+perform_prompt_complete (GSimpleAsyncResult *res,
+ gboolean dismissed)
+{
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+ closure->dismissed = dismissed;
+ if (closure->completed)
+ return;
+ closure->completed = TRUE;
+
+ if (closure->signal)
+ g_dbus_connection_signal_unsubscribe (closure->connection, closure->signal);
+ closure->signal = 0;
+
+ if (closure->watch)
+ g_bus_unwatch_name (closure->watch);
+ closure->watch = 0;
+
+ if (closure->cancelled_sig)
+ g_signal_handler_disconnect (closure->async_cancellable, closure->cancelled_sig);
+ closure->cancelled_sig = 0;
+
+ g_simple_async_result_complete (res);
+}
+
+static void
+on_prompt_completed (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GSecretPrompt *self = GSECRET_PROMPT (g_async_result_get_source_object (user_data));
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ gboolean dismissed;
+
+ closure->prompting = FALSE;
+
+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(bv)"))) {
+ g_warning ("GSecretPrompt received invalid %s signal of type %s",
+ signal_name, g_variant_get_type_string (parameters));
+ perform_prompt_complete (res, TRUE);
+
+ } else {
+ g_return_if_fail (self->pv->last_result == NULL);
+ g_variant_get (parameters, "(bv)", &dismissed, &self->pv->last_result);
+ perform_prompt_complete (res, dismissed);
+ }
+
+ g_object_unref (self);
+}
+
+static void
+on_prompt_prompted (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretPrompt *self = GSECRET_PROMPT (source);
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error);
+
+ if (retval)
+ g_variant_unref (retval);
+ if (closure->vanished)
+ g_clear_error (&error);
+
+ if (error != NULL) {
+ g_simple_async_result_take_error (res, error);
+ perform_prompt_complete (res, TRUE);
+
+ } else {
+ g_atomic_int_inc (&self->pv->prompted);
+
+ /* And now we wait for the signal */
+ closure->prompting = TRUE;
+ }
+
+ g_object_unref (res);
+}
+
+static void
+on_prompt_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ closure->vanished = TRUE;
+ g_cancellable_cancel (closure->call_cancellable);
+ perform_prompt_complete (res, TRUE);
+}
+
+static void
+on_prompt_dismissed (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretPrompt *self = GSECRET_PROMPT (source);
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error);
+
+ if (retval)
+ g_variant_unref (retval);
+ if (closure->vanished)
+ g_clear_error (&error);
+
+ if (error != NULL) {
+ g_simple_async_result_take_error (res, error);
+ perform_prompt_complete (res, TRUE);
+ }
+
+ g_object_unref (res);
+}
+
+static void
+on_prompt_cancelled (GCancellable *cancellable,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ PerformClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretPrompt *self = GSECRET_PROMPT (g_async_result_get_source_object (user_data));
+
+ /* Instead of cancelling our dbus calls, we cancel the prompt itself via this dbus call */
+
+ g_dbus_proxy_call (G_DBUS_PROXY (self), "Dismiss", g_variant_new ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
+ closure->call_cancellable,
+ on_prompt_dismissed, g_object_ref (res));
+
+ g_object_unref (self);
+}
+
+void
+gsecret_prompt_perform (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ PerformClosure *closure;
+ const gchar *owner_name;
+ const gchar *object_path;
+ GDBusProxy *proxy;
+ gchar *window;
+
+ g_return_if_fail (GSECRET_IS_PROMPT (self));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ if (g_atomic_int_get (&self->pv->prompted)) {
+ g_warning ("The prompt object has already had its prompt called.");
+ return;
+ }
+
+ proxy = G_DBUS_PROXY (self);
+
+ res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gsecret_prompt_perform);
+ closure = g_slice_new0 (PerformClosure);
+ closure->connection = g_object_ref (g_dbus_proxy_get_connection (proxy));
+ closure->call_cancellable = g_cancellable_new ();
+ closure->async_cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, closure, perform_closure_free);
+
+ if (window_id == 0)
+ window = g_strdup ("");
+ else
+ window = g_strdup_printf ("%lu", window_id);
+
+ owner_name = g_dbus_proxy_get_name_owner (proxy);
+ object_path = g_dbus_proxy_get_object_path (proxy);
+
+ closure->signal = g_dbus_connection_signal_subscribe (closure->connection, owner_name,
+ GSECRET_PROMPT_INTERFACE,
+ GSECRET_PROMPT_SIGNAL_COMPLETED,
+ object_path, NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_prompt_completed,
+ g_object_ref (res),
+ g_object_unref);
+
+ closure->watch = g_bus_watch_name_on_connection (closure->connection, owner_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE, NULL,
+ on_prompt_vanished,
+ g_object_ref (res),
+ g_object_unref);
+
+ if (closure->async_cancellable) {
+ closure->cancelled_sig = g_cancellable_connect (closure->async_cancellable,
+ G_CALLBACK (on_prompt_cancelled),
+ res, NULL);
+ }
+
+ g_dbus_proxy_call (proxy, "Prompt", g_variant_new ("(s)", window),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
+ closure->call_cancellable, on_prompt_prompted, g_object_ref (res));
+
+ g_free (window);
+ g_object_unref (res);
+}
+
+gboolean
+gsecret_prompt_perform_finish (GSecretPrompt *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ PerformClosure *closure;
+ GSimpleAsyncResult *res;
+
+ g_return_val_if_fail (GSECRET_IS_PROMPT (self), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+ gsecret_prompt_perform), FALSE);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ return !closure->dismissed;
+}
+
+GVariant *
+gsecret_prompt_get_result_value (GSecretPrompt *self)
+{
+ g_return_val_if_fail (GSECRET_IS_PROMPT (self), NULL);
+
+ if (self->pv->last_result)
+ return g_variant_ref (self->pv->last_result);
+
+ return NULL;
+}
diff --git a/library/gsecret-prompt.h b/library/gsecret-prompt.h
index cb43339..7abfb93 100644
--- a/library/gsecret-prompt.h
+++ b/library/gsecret-prompt.h
@@ -15,6 +15,8 @@
#include <gio/gio.h>
+#include "gsecret-types.h"
+
G_BEGIN_DECLS
#define GSECRET_TYPE_PROMPT (gsecret_prompt_get_type ())
@@ -24,13 +26,13 @@ G_BEGIN_DECLS
#define GSECRET_IS_PROMPT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_PROMPT))
#define GSECRET_PROMPT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_PROMPT, GSecretPromptClass))
-typedef struct _GSecretPrompt GSecretPrompt;
typedef struct _GSecretPromptClass GSecretPromptClass;
typedef struct _GSecretPromptPrivate GSecretPromptPrivate;
struct _GSecretPromptClass {
GDBusProxyClass parent_class;
- padding;
+
+ gpointer padding[8];
};
struct _GSecretPrompt {
@@ -38,19 +40,32 @@ struct _GSecretPrompt {
GSecretPromptPrivate *pv;
};
-GType gsecret_service_get_type (void) G_GNUC_CONST;
+GType gsecret_prompt_get_type (void) G_GNUC_CONST;
+
+GSecretPrompt * gsecret_prompt_instance (GSecretService *service,
+ const gchar *prompt_path);
-GSecretService* gsecret_collection_xxx_new (void);
+gboolean gsecret_prompt_run (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
+ GError **error);
-GSecretPrompt* gsecret_prompt_instance (GDBusConnection *connection,
- const gchar *object_path,
+gboolean gsecret_prompt_perform_sync (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
GError **error);
-GSecretPrompt* gsecret_prompt_instance_sync (GDBusConnection *connection,
- const gchar *object_path);
+void gsecret_prompt_perform (GSecretPrompt *self,
+ gulong window_id,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gsecret_prompt_perform_finish (GSecretPrompt *self,
+ GAsyncResult *result,
+ GError **error);
- gsecret_prompt_perform
- gsecret_prompt_dismiss
+GVariant * gsecret_prompt_get_result_value (GSecretPrompt *self);
G_END_DECLS
diff --git a/library/gsecret-service.c b/library/gsecret-service.c
index 50e5be3..44c3e70 100644
--- a/library/gsecret-service.c
+++ b/library/gsecret-service.c
@@ -13,6 +13,7 @@
#include "config.h"
#include "gsecret-dbus-generated.h"
+#include "gsecret-item.h"
#include "gsecret-private.h"
#include "gsecret-service.h"
#include "gsecret-types.h"
@@ -36,6 +37,8 @@ EGG_SECURE_GLIB_DEFINITIONS ();
EGG_SECURE_DECLARE (secret_service);
+static const gchar *default_bus_name = GSECRET_SERVICE_BUS_NAME;
+
#define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7"
#define ALGORITHMS_PLAIN "plain"
@@ -60,6 +63,45 @@ static gpointer service_instance = NULL;
G_DEFINE_TYPE (GSecretService, gsecret_service, G_TYPE_DBUS_PROXY);
+typedef struct {
+ GAsyncResult *result;
+ GMainContext *context;
+ GMainLoop *loop;
+} SyncClosure;
+
+static SyncClosure *
+sync_closure_new (void)
+{
+ SyncClosure *closure;
+
+ closure = g_new0 (SyncClosure, 1);
+
+ closure->context = g_main_context_new ();
+ closure->loop = g_main_loop_new (closure->context, FALSE);
+
+ return closure;
+}
+
+static void
+sync_closure_free (gpointer data)
+{
+ SyncClosure *closure = data;
+
+ g_clear_object (&closure->result);
+ g_main_loop_unref (closure->loop);
+ g_main_context_unref (closure->context);
+}
+
+static void
+on_sync_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ SyncClosure *closure = user_data;
+ closure->result = g_object_ref (result);
+ g_main_loop_quit (closure->loop);
+}
+
static void
gsecret_session_free (gpointer data)
{
@@ -95,6 +137,65 @@ gsecret_service_finalize (GObject *obj)
G_OBJECT_CLASS (gsecret_service_parent_class)->finalize (obj);
}
+static gboolean
+gsecret_service_real_prompt_sync (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return gsecret_prompt_perform_sync (prompt, 0, cancellable, error);
+}
+
+static void
+on_real_prompt_completed (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_prompt_perform_finish (GSECRET_PROMPT (source), result, &error);
+ g_simple_async_result_set_op_res_gboolean (res, ret);
+ if (error != NULL)
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+
+ g_object_unref (res);
+}
+
+static void
+gsecret_service_real_prompt_async (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gsecret_service_real_prompt_async);
+
+ gsecret_prompt_perform (prompt, 0, cancellable,
+ on_real_prompt_completed,
+ g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+static gboolean
+gsecret_service_real_prompt_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
+
+ return g_simple_async_result_get_op_res_gboolean (res);
+}
+
static void
gsecret_service_class_init (GSecretServiceClass *klass)
{
@@ -102,9 +203,20 @@ gsecret_service_class_init (GSecretServiceClass *klass)
object_class->finalize = gsecret_service_finalize;
+ klass->prompt_sync = gsecret_service_real_prompt_sync;
+ klass->prompt_async = gsecret_service_real_prompt_async;
+ klass->prompt_finish = gsecret_service_real_prompt_finish;
+
g_type_class_add_private (klass, sizeof (GSecretServicePrivate));
}
+void
+_gsecret_service_set_default_bus_name (const gchar *bus_name)
+{
+ g_return_if_fail (bus_name != NULL);
+ default_bus_name = bus_name;
+}
+
static void
on_service_instance_gone (gpointer user_data,
GObject *where_the_object_was)
@@ -138,7 +250,7 @@ _gsecret_service_bare_instance (GDBusConnection *connection,
/* Alternate bus name is only used for testing */
if (bus_name == NULL)
- bus_name = GSECRET_SERVICE_BUS_NAME;
+ bus_name = default_bus_name;
service = g_initable_new (GSECRET_TYPE_SERVICE, NULL, &error,
"g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
@@ -172,6 +284,115 @@ _gsecret_service_bare_instance (GDBusConnection *connection,
return service;
}
+typedef struct {
+ GCancellable *cancellable;
+ GSecretService *service;
+ gboolean ensure_session;
+ gchar *bus_name;
+} ConnectClosure;
+
+static void
+connect_closure_free (gpointer data)
+{
+ ConnectClosure *closure = data;
+ g_clear_object (&closure->cancellable);
+ g_clear_object (&closure->service);
+ g_slice_free (ConnectClosure, closure);
+}
+
+static void
+on_connect_ensure (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GError *error = NULL;
+
+ gsecret_service_ensure_session_finish (GSECRET_SERVICE (source), result, &error);
+ if (error != NULL)
+ g_simple_async_result_take_error (res, error);
+
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+}
+
+static void
+on_connect_bus (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ ConnectClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GDBusConnection *connection;
+ GError *error = NULL;
+
+ connection = g_bus_get_finish (result, &error);
+ if (error == NULL) {
+ closure->service = _gsecret_service_bare_instance (connection, closure->bus_name);
+ if (closure->ensure_session)
+ gsecret_service_ensure_session (closure->service, closure->cancellable,
+ on_connect_ensure, g_object_ref (res));
+
+ else
+ g_simple_async_result_complete (res);
+
+ g_object_unref (connection);
+
+ } else {
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+ }
+
+ g_object_unref (res);
+}
+
+void
+_gsecret_service_bare_connect (const gchar *bus_name,
+ gboolean ensure_session,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ ConnectClosure *closure;
+
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ if (bus_name == NULL)
+ bus_name = default_bus_name;
+
+ res = g_simple_async_result_new (NULL, callback, user_data,
+ _gsecret_service_bare_connect);
+ closure = g_slice_new0 (ConnectClosure);
+ closure->bus_name = g_strdup (bus_name);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ closure->ensure_session = ensure_session;
+ g_simple_async_result_set_op_res_gpointer (res, closure, connect_closure_free);
+
+ g_bus_get (G_BUS_TYPE_SESSION, cancellable, on_connect_bus, g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+GSecretService *
+_gsecret_service_bare_connect_finish (GAsyncResult *result,
+ GError **error)
+{
+ ConnectClosure *closure;
+ GSimpleAsyncResult *res;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+ _gsecret_service_bare_connect), NULL);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return NULL;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ return g_object_ref (closure->service);
+}
+
const gchar *
gsecret_service_get_session_algorithms (GSecretService *self)
{
@@ -1271,3 +1492,490 @@ gsecret_service_get_secrets_for_paths_sync (GSecretService *self,
return values;
}
+
+gboolean
+gsecret_service_prompt_sync (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GSecretServiceClass *klass;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (GSECRET_IS_PROMPT (prompt), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ klass = GSECRET_SERVICE_GET_CLASS (self);
+ g_return_val_if_fail (klass->prompt_sync != NULL, FALSE);
+
+ return (klass->prompt_sync) (self, prompt, cancellable, error);
+}
+
+void
+gsecret_service_prompt_path (GSecretService *self,
+ const gchar *prompt_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSecretPrompt *prompt;
+
+ g_return_if_fail (GSECRET_IS_SERVICE (self));
+ g_return_if_fail (prompt_path != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ prompt = gsecret_prompt_instance (self, prompt_path);
+
+ gsecret_service_prompt (self, prompt, cancellable, callback, user_data);
+
+ g_object_unref (prompt);
+}
+
+void
+gsecret_service_prompt (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSecretServiceClass *klass;
+
+ g_return_if_fail (GSECRET_IS_SERVICE (self));
+ g_return_if_fail (GSECRET_IS_PROMPT (prompt));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ klass = GSECRET_SERVICE_GET_CLASS (self);
+ g_return_if_fail (klass->prompt_async != NULL);
+
+ (klass->prompt_async) (self, prompt, cancellable, callback, user_data);
+}
+
+gboolean
+gsecret_service_prompt_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSecretServiceClass *klass;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ klass = GSECRET_SERVICE_GET_CLASS (self);
+ g_return_val_if_fail (klass->prompt_finish != NULL, FALSE);
+
+ return (klass->prompt_finish) (self, result, error);
+}
+
+#if 0
+
+void
+gsecret_service_store_password (GSecretService *self,
+ const GSecretSchema *schema,
+ const gchar *collection_path,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+
+}
+
+gboolean
+gsecret_service_store_password_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+
+}
+
+void
+gsecret_service_store_password_sync (GSecretService *self,
+ const GSecretSchema *schema,
+ const gchar *collection,
+ const gchar *display_name,
+ const gchar *password,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+
+}
+
+void
+gsecret_service_lookup_password (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+
+}
+
+gchar *
+gsecret_service_lookup_password_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+
+}
+
+gchar *
+gsecret_service_lookup_password_sync (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+
+}
+
+#endif
+
+typedef struct {
+ GCancellable *cancellable;
+ gboolean deleted;
+} DeleteClosure;
+
+static void
+delete_closure_free (gpointer data)
+{
+ DeleteClosure *closure = data;
+ g_clear_object (&closure->cancellable);
+ g_slice_free (DeleteClosure, closure);
+}
+
+static void
+on_delete_prompted (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GError *error = NULL;
+
+ gsecret_service_prompt_finish (GSECRET_SERVICE (source), result, &error);
+
+ if (error == NULL)
+ closure->deleted = TRUE;
+ else
+ g_simple_async_result_take_error (res, error);
+
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+}
+
+static void
+on_delete_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretService *self = GSECRET_SERVICE (g_async_result_get_source_object (user_data));
+ const gchar *prompt_path;
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
+ if (error == NULL) {
+ g_variant_get (retval, "(&o)", &prompt_path);
+
+ if (_gsecret_util_empty_path (prompt_path)) {
+ closure->deleted = TRUE;
+ g_simple_async_result_complete (res);
+
+ } else {
+ gsecret_service_prompt_path (self, prompt_path,
+ closure->cancellable,
+ on_delete_prompted,
+ g_object_ref (res));
+ }
+
+ g_variant_unref (retval);
+
+ } else {
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+ }
+
+ g_object_unref (self);
+ g_object_unref (res);
+}
+
+void
+gsecret_service_delete_path (GSecretService *self,
+ const gchar *item_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ DeleteClosure *closure;
+
+ g_return_if_fail (GSECRET_IS_SERVICE (self));
+ g_return_if_fail (item_path != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gsecret_service_delete_path);
+ closure = g_slice_new0 (DeleteClosure);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
+
+ g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)),
+ g_dbus_proxy_get_name (G_DBUS_PROXY (self)),
+ item_path, GSECRET_ITEM_INTERFACE,
+ "Delete", g_variant_new ("()"), G_VARIANT_TYPE ("(o)"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
+ cancellable, on_delete_complete, g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+gboolean
+gsecret_service_delete_path_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *res;
+ DeleteClosure *closure;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+ gsecret_service_delete_path), FALSE);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ return closure->deleted;
+}
+
+gboolean
+gsecret_service_delete_path_sync (GSecretService *self,
+ const gchar *item_path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SyncClosure *closure;
+ gboolean result;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (item_path != NULL, FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ closure = sync_closure_new ();
+ g_main_context_push_thread_default (closure->context);
+
+ gsecret_service_delete_path (self, item_path, cancellable, on_sync_result, closure);
+
+ g_main_loop_run (closure->loop);
+
+ result = gsecret_service_delete_path_finish (self, closure->result, error);
+
+ g_main_context_pop_thread_default (closure->context);
+ sync_closure_free (closure);
+
+ return result;
+}
+
+static void
+on_delete_password_complete (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ GSecretService *self = GSECRET_SERVICE (g_async_result_get_source_object (user_data));
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GError *error = NULL;
+
+ closure->deleted = gsecret_service_delete_path_finish (self, result, &error);
+ if (error != NULL)
+ g_simple_async_result_take_error (res, error);
+
+ g_simple_async_result_complete (res);
+
+ g_object_unref (self);
+ g_object_unref (res);
+}
+
+static void
+on_search_delete_password (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+ DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GSecretService *self = GSECRET_SERVICE (g_async_result_get_source_object (user_data));
+ const gchar *path = NULL;
+ GError *error = NULL;
+ gchar **locked;
+ gchar **unlocked;
+
+ gsecret_service_search_for_paths_finish (self, result, &unlocked, &locked, &error);
+ if (error != NULL) {
+ g_simple_async_result_take_error (res, error);
+ g_simple_async_result_complete (res);
+
+ } else {
+ /* Choose the first path */
+ if (unlocked && unlocked[0])
+ path = unlocked[0];
+ else if (locked && locked[0])
+ path = locked[0];
+
+ /* Nothing to delete? */
+ if (path == NULL) {
+ closure->deleted = FALSE;
+ g_simple_async_result_complete (res);
+
+ /* Delete the first path */
+ } else {
+ closure->deleted = TRUE;
+ gsecret_service_delete_path (self, path,
+ closure->cancellable,
+ on_delete_password_complete,
+ g_object_ref (res));
+ }
+ }
+
+ g_strfreev (locked);
+ g_strfreev (unlocked);
+ g_object_unref (self);
+ g_object_unref (res);
+}
+
+void
+gsecret_service_delete_password (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...)
+{
+ GHashTable *attributes;
+ va_list va;
+
+ g_return_if_fail (GSECRET_SERVICE (self));
+ g_return_if_fail (schema != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ va_start (va, user_data);
+ attributes = _gsecret_util_attributes_for_varargs (schema, va);
+ va_end (va);
+
+ gsecret_service_delete_passwordv (self, attributes, cancellable,
+ callback, user_data);
+
+ g_hash_table_unref (attributes);
+}
+
+void
+gsecret_service_delete_passwordv (GSecretService *self,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ DeleteClosure *closure;
+
+ g_return_if_fail (GSECRET_SERVICE (self));
+ g_return_if_fail (attributes != NULL);
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ gsecret_service_delete_password);
+ closure = g_slice_new0 (DeleteClosure);
+ closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
+
+ gsecret_service_search_for_paths (self, attributes, cancellable,
+ on_search_delete_password, g_object_ref (res));
+
+ g_object_unref (res);
+}
+
+gboolean
+gsecret_service_delete_password_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *res;
+ DeleteClosure *closure;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+ gsecret_service_delete_password), FALSE);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return FALSE;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ return closure->deleted;
+}
+
+gboolean
+gsecret_service_delete_password_sync (GSecretService *self,
+ const GSecretSchema* schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+ GHashTable *attributes;
+ gboolean result;
+ va_list va;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ va_start (va, error);
+ attributes = _gsecret_util_attributes_for_varargs (schema, va);
+ va_end (va);
+
+ result = gsecret_service_delete_passwordv_sync (self, attributes, cancellable, error);
+
+ g_hash_table_unref (attributes);
+
+ return result;
+}
+
+gboolean
+gsecret_service_delete_passwordv_sync (GSecretService *self,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SyncClosure *closure;
+ gboolean result;
+
+ g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ closure = sync_closure_new ();
+ g_main_context_push_thread_default (closure->context);
+
+ gsecret_service_delete_passwordv (self, attributes, cancellable,
+ on_sync_result, closure);
+
+ g_main_loop_run (closure->loop);
+
+ result = gsecret_service_delete_password_finish (self, closure->result, error);
+
+ g_main_context_pop_thread_default (closure->context);
+ sync_closure_free (closure);
+
+ return result;
+}
diff --git a/library/gsecret-service.h b/library/gsecret-service.h
index af13f19..a65a621 100644
--- a/library/gsecret-service.h
+++ b/library/gsecret-service.h
@@ -15,6 +15,8 @@
#include <gio/gio.h>
+#include "gsecret-prompt.h"
+#include "gsecret-types.h"
#include "gsecret-value.h"
G_BEGIN_DECLS
@@ -26,19 +28,26 @@ G_BEGIN_DECLS
#define GSECRET_IS_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_SERVICE))
#define GSECRET_SERVICE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_SERVICE, GSecretServiceClass))
-typedef struct _GSecretService GSecretService;
typedef struct _GSecretServiceClass GSecretServiceClass;
typedef struct _GSecretServicePrivate GSecretServicePrivate;
struct _GSecretServiceClass {
GDBusProxyClass parent_class;
- GType collection_type;
- GType item_type;
+ gboolean (*prompt_sync) (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GError **error);
-#if 0
- padding;
-#endif
+ void (*prompt_async) (GSecretService *self,
+ GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+ gboolean (*prompt_finish) (GSecretService *self,
+ GAsyncResult *result,
+ GError **error);
};
struct _GSecretService {
@@ -186,34 +195,132 @@ void gsecret_service_unlock (GSecretService *se
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
+#endif
-gboolean gsecret_service_
- GList **unlocked,
- GSecretPrompt *prompt,
+gint gsecret_service_unlock_paths_sync (GSecretService *self,
+ const gchar **paths,
+ GCancellable *cancellable,
+ gchar ***unlocked,
GError **error);
-gboolean gsecret_service_unlock (GSecretService *self,
- GList *objects,
- GList **unlocked,
+void gsecret_service_unlock_paths (GSecretService *self,
+ const gchar **paths,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gint gsecret_service_unlock_paths_finish (GSecretService *self,
+ GAsyncResult *result,
+ gchar ***unlocked,
+ GError **error);
+
+gboolean gsecret_service_prompt_sync (GSecretService *self,
GSecretPrompt *prompt,
+ GCancellable *cancellable,
GError **error);
-gboolean gsecret_service_unlock_for_paths (GSecretService *self,
- GList *objects,
- GList **unlocked,
+void gsecret_service_prompt (GSecretService *self,
GSecretPrompt *prompt,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+void gsecret_service_prompt_path (GSecretService *self,
+ const gchar *prompt_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gsecret_service_prompt_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error);
+
+#if 0
+void gsecret_service_store_password (GSecretService *self,
+ const GSecretSchema *schema,
+ const gchar *collection_path,
+ const gchar *label,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean gsecret_service_store_password_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error);
+
+void gsecret_service_store_password_sync (GSecretService *self,
+ const GSecretSchema *schema,
+ const gchar *collection,
+ const gchar *display_name,
+ const gchar *password,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gsecret_service_lookup_password (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gchar * gsecret_service_lookup_password_finish (GSecretService *self,
+ GAsyncResult *result,
+ GError **error);
+
+gchar * gsecret_service_lookup_password_sync (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+#endif
+
+void gsecret_service_delete_path (GSecretService *self,
+ const gchar *item_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gsecret_service_delete_path_finish (GSecretService *self,
+ GAsyncResult *result,
GError **error);
-GHashTable* gsecret_service_get_secrets (GList *items,
+gboolean gsecret_service_delete_path_sync (GSecretService *self,
+ const gchar *item_path,
+ GCancellable *cancellable,
GError **error);
-GHashTable* gsecret_service_get_secrets_for_paths (GList *items,
+void gsecret_service_delete_password (GSecretService *self,
+ const GSecretSchema *schema,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gsecret_service_delete_passwordv (GSecretService *self,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gsecret_service_delete_password_finish (GSecretService *self,
+ GAsyncResult *result,
GError **error);
-gsecret_collection_create_collection
+gboolean gsecret_service_delete_password_sync (GSecretService *self,
+ const GSecretSchema* schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
-GList* gsecret_service_get_collections
+gboolean gsecret_service_delete_passwordv_sync (GSecretService *self,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error);
+#if 0
GSecretCollection* gsecret_service_read_alias (GSecretService *self,
const gchar *alias,
GError **error);
diff --git a/library/gsecret-types.h b/library/gsecret-types.h
index eadfd87..486d91e 100644
--- a/library/gsecret-types.h
+++ b/library/gsecret-types.h
@@ -25,6 +25,36 @@ typedef enum {
GSECRET_ERROR_PROTOCOL = 1,
} GSecretError;
+typedef enum {
+ GSECRET_ATTRIBUTE_BOOLEAN,
+ GSECRET_ATTRIBUTE_STRING,
+ GSECRET_ATTRIBUTE_INTEGER
+} GSecretSchemaType;
+
+typedef struct {
+ const gchar *schema_name;
+ struct {
+ const gchar* name;
+ GSecretSchemaType type;
+ } attributes[32];
+
+ /* <private> */
+ gpointer reserved1;
+ gpointer reserved2;
+ gpointer reserved3;
+ gpointer reserved4;
+ gpointer reserved5;
+ gpointer reserved6;
+ gpointer reserved7;
+ gpointer reserved8;
+} GSecretSchema;
+
+typedef struct _GSecretCollection GSecretCollection;
+typedef struct _GSecretItem GSecretItem;
+typedef struct _GSecretPrompt GSecretPrompt;
+typedef struct _GSecretService GSecretService;
+typedef struct _GSecretValue GSecretValue;
+
G_END_DECLS
#endif /* __G_SERVICE_H___ */
diff --git a/library/gsecret-util.c b/library/gsecret-util.c
index 0fd98dd..45c97f1 100644
--- a/library/gsecret-util.c
+++ b/library/gsecret-util.c
@@ -72,6 +72,13 @@ _gsecret_util_parent_path (const gchar *path)
return g_strndup (path, pos - path);
}
+gboolean
+_gsecret_util_empty_path (const gchar *path)
+{
+ g_return_val_if_fail (path != NULL, TRUE);
+ return (g_str_equal (path, "") || g_str_equal (path, "/"));
+}
+
GVariant *
_gsecret_util_variant_for_attributes (GHashTable *attributes)
{
@@ -91,3 +98,71 @@ _gsecret_util_variant_for_attributes (GHashTable *attributes)
return g_variant_builder_end (&builder);
}
+
+GHashTable *
+_gsecret_util_attributes_for_varargs (const GSecretSchema *schema,
+ va_list args)
+{
+ const gchar *attribute_name;
+ GSecretSchemaType type;
+ GHashTable *attributes;
+ const gchar *string;
+ gboolean type_found;
+ gchar *value = NULL;
+ gboolean boolean;
+ gint integer;
+ gint i;
+
+ attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ for (;;) {
+ attribute_name = va_arg (args, const gchar *);
+ if (attribute_name == NULL)
+ break;
+
+ type_found = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (schema->attributes); ++i) {
+ if (!schema->attributes[i].name)
+ break;
+ if (g_str_equal (schema->attributes[i].name, attribute_name)) {
+ type_found = TRUE;
+ type = schema->attributes[i].type;
+ break;
+ }
+ }
+
+ if (!type_found) {
+ g_warning ("The attribute '%s' was not found in the password schema.", attribute_name);
+ g_hash_table_unref (attributes);
+ return NULL;
+ }
+
+ switch (type) {
+ case GSECRET_ATTRIBUTE_BOOLEAN:
+ boolean = va_arg (args, gboolean);
+ value = g_strdup (boolean ? "true" : "false");
+ break;
+ case GSECRET_ATTRIBUTE_STRING:
+ string = va_arg (args, gchar *);
+ if (!g_utf8_validate (string, -1, NULL)) {
+ g_warning ("The value for attribute '%s' was not a valid utf-8 string.", attribute_name);
+ g_hash_table_unref (attributes);
+ return NULL;
+ }
+ value = g_strdup (string);
+ break;
+ case GSECRET_ATTRIBUTE_INTEGER:
+ integer = va_arg (args, gint);
+ value = g_strdup_printf ("%d", integer);
+ break;
+ default:
+ g_warning ("The password attribute '%s' has an invalid type in the password schema.", attribute_name);
+ g_hash_table_unref (attributes);
+ return NULL;
+ }
+
+ g_hash_table_insert (attributes, g_strdup (attribute_name), value);
+ }
+
+ return attributes;
+}
diff --git a/library/gsecret-value.h b/library/gsecret-value.h
index ebaa3d3..2046467 100644
--- a/library/gsecret-value.h
+++ b/library/gsecret-value.h
@@ -15,12 +15,12 @@
#include <gio/gio.h>
+#include "gsecret-types.h"
+
G_BEGIN_DECLS
#define GSECRET_TYPE_VALUE (gsecret_service_get_type ())
-typedef struct _GSecretValue GSecretValue;
-
GType gsecret_value_get_type (void) G_GNUC_CONST;
GSecretValue* gsecret_value_new (const gchar *secret,
diff --git a/library/org.freedesktop.Secrets.xml b/library/org.freedesktop.Secrets.xml
index f9749f8..8182df4 100644
--- a/library/org.freedesktop.Secrets.xml
+++ b/library/org.freedesktop.Secrets.xml
@@ -68,109 +68,93 @@
</interface>
- <node name="/org/freedesktop/Secrets/collection/xxxx">
+ <interface name="org.freedesktop.Secret.Collection">
- <interface name="org.freedesktop.Secret.Collection">
+ <property name="Items" type="ao" access="read"/>
+ <property name="Label" type="s" access="readwrite"/>
+ <property name="Locked" type="b" access="read"/>
+ <property name="Created" type="t" access="read"/>
+ <property name="Modified" type="t" access="read"/>
- <property name="Items" type="ao" access="read"/>
- <property name="Label" type="s" access="readwrite"/>
- <property name="Locked" type="b" access="read"/>
- <property name="Created" type="t" access="read"/>
- <property name="Modified" type="t" access="read"/>
-
- <method name="Delete">
- <arg name="prompt" type="o" direction="out"/>
- </method>
-
- <method name="SearchItems">
- <arg name="attributes" type="a{ss}" direction="in"/>
- <arg name="results" type="ao" direction="out"/>
- </method>
-
- <method name="CreateItem">
- <arg name="properties" type="a{sv}" direction="in"/>
- <arg name="secret" type="(oayays)" direction="in"/>
- <arg name="replace" type="b" direction="in"/>
- <arg name="item" type="o" direction="out"/>
- <arg name="prompt" type="o" direction="out"/>
- </method>
-
- <signal name="ItemCreated">
- <arg name="item" type="o"/>
- </signal>
-
- <signal name="ItemDeleted">
- <arg name="item" type="o"/>
- </signal>
-
- <signal name="ItemChanged">
- <arg name="item" type="o"/>
- </signal>
-
- </interface>
-
- <node name="/org/freedesktop/Secret/collection/xxxx/iiii">
-
- <interface name="org.freedesktop.Secret.Item">
+ <method name="Delete">
+ <arg name="prompt" type="o" direction="out"/>
+ </method>
- <property name="Locked" type="b" access="read"/>
+ <method name="SearchItems">
+ <arg name="attributes" type="a{ss}" direction="in"/>
+ <arg name="results" type="ao" direction="out"/>
+ </method>
- <property name="Attributes" type="a{ss}" access="readwrite"/>
+ <method name="CreateItem">
+ <arg name="properties" type="a{sv}" direction="in"/>
+ <arg name="secret" type="(oayays)" direction="in"/>
+ <arg name="replace" type="b" direction="in"/>
+ <arg name="item" type="o" direction="out"/>
+ <arg name="prompt" type="o" direction="out"/>
+ </method>
- <property name="Label" type="s" access="readwrite"/>
+ <signal name="ItemCreated">
+ <arg name="item" type="o"/>
+ </signal>
- <property name="Created" type="t" access="read"/>
+ <signal name="ItemDeleted">
+ <arg name="item" type="o"/>
+ </signal>
- <property name="Modified" type="t" access="read"/>
+ <signal name="ItemChanged">
+ <arg name="item" type="o"/>
+ </signal>
- <method name="Delete">
- <arg name="Prompt" type="o" direction="out"/>
- </method>
+ </interface>
- <method name="GetSecret">
- <arg name="session" type="o" direction="in"/>
- <arg name="secret" type="(oayays)" direction="out"/>
- </method>
+ <interface name="org.freedesktop.Secret.Item">
- <method name="SetSecret">
- <arg name="secret" type="(oayays)" direction="in"/>
- </method>
+ <property name="Locked" type="b" access="read"/>
- </interface>
+ <property name="Attributes" type="a{ss}" access="readwrite"/>
- </node>
+ <property name="Label" type="s" access="readwrite"/>
- </node>
+ <property name="Created" type="t" access="read"/>
- <node name="/org/freedesktop/Secret/session/ssss">
+ <property name="Modified" type="t" access="read"/>
- <interface name="org.freedesktop.Secret.Session">
+ <method name="Delete">
+ <arg name="Prompt" type="o" direction="out"/>
+ </method>
- <method name="Close">
- </method>
+ <method name="GetSecret">
+ <arg name="session" type="o" direction="in"/>
+ <arg name="secret" type="(oayays)" direction="out"/>
+ </method>
- </interface>
+ <method name="SetSecret">
+ <arg name="secret" type="(oayays)" direction="in"/>
+ </method>
- </node>
+ </interface>
- <node name="/org/freedesktop/Secret/prompts/pppp">
- <interface name="org.freedesktop.Secret.Prompt">
+ <interface name="org.freedesktop.Secret.Session">
- <method name="Prompt">
- <arg name="window-id" type="s" direction="in"/>
- </method>
+ <method name="Close">
+ </method>
- <method name="Dismiss">
- </method>
+ </interface>
- <signal name="Completed">
- <arg name="dismissed" type="b"/>
- <arg name="result" type="v"/>
- </signal>
+ <interface name="org.freedesktop.Secret.Prompt">
- </interface>
+ <method name="Prompt">
+ <arg name="window_id" type="s" direction="in"/>
+ </method>
- </node>
+ <method name="Dismiss">
+ </method>
+ <signal name="Completed">
+ <arg name="dismissed" type="b"/>
+ <arg name="result" type="v"/>
+ </signal>
+ </interface>
+s
</node>
diff --git a/library/tests/Makefile.am b/library/tests/Makefile.am
index 9604b24..2cd4221 100644
--- a/library/tests/Makefile.am
+++ b/library/tests/Makefile.am
@@ -11,8 +11,10 @@ LDADD = \
$(NULL)
TEST_PROGS = \
+ test-prompt \
test-service \
test-session \
+ test-password \
$(NULL)
check_PROGRAMS = \
diff --git a/library/tests/mock-service-delete.py b/library/tests/mock-service-delete.py
new file mode 100644
index 0000000..40a932d
--- /dev/null
+++ b/library/tests/mock-service-delete.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+import dbus
+import mock
+import sys
+
+service = mock.SecretService()
+service.add_standard_objects()
+
+collection = mock.SecretCollection(service, "to_delete", locked=False)
+mock.SecretItem(collection, "item", attributes={ "number": "1", "string": "one", "even": "false" }, secret="uno")
+mock.SecretItem(collection, "confirm", attributes={ "number": "2", "string": "two", "even": "true" }, secret="dos", confirm=True)
+
+collection = mock.SecretCollection(service, "two_delete", locked=True)
+mock.SecretItem(collection, "locked", attributes={ "number": "3", "string": "three", "even": "false" }, secret="tres")
+
+service.listen() \ No newline at end of file
diff --git a/library/tests/mock-service-prompt.py b/library/tests/mock-service-prompt.py
new file mode 100644
index 0000000..785b147
--- /dev/null
+++ b/library/tests/mock-service-prompt.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+import dbus
+import mock
+import sys
+
+class ErrorPrompt(mock.SecretPrompt):
+ def __init__(self, service, sender, prompt_name):
+ mock.SecretPrompt.__init__(self, service, sender, prompt_name)
+
+ @dbus.service.method('org.freedesktop.Secret.Prompt')
+ def Prompt(self, window_id):
+ raise mock.NotSupported("This should cause prompting to fail")
+
+class VanishPrompt(mock.SecretPrompt):
+ def __init__(self, service, sender, prompt_name):
+ mock.SecretPrompt.__init__(self, service, sender, prompt_name)
+
+ @dbus.service.method('org.freedesktop.Secret.Prompt')
+ def Prompt(self, window_id):
+ sys.exit(0)
+
+class WindowPrompt(mock.SecretPrompt):
+ def __init__(self, service, sender, prompt_name):
+ mock.SecretPrompt.__init__(self, service, sender, prompt_name)
+
+ @dbus.service.method('org.freedesktop.Secret.Prompt')
+ def Prompt(self, window_id):
+ self.result = dbus.String(window_id, variant_level=1)
+ mock.SecretPrompt.Prompt(self, window_id)
+
+service = mock.SecretService()
+service.add_standard_objects()
+
+mock.SecretPrompt(service, None, "simple")
+mock.SecretPrompt(service, None, "delay", delay=0.5)
+mock.SecretPrompt(service, None, "result", result=dbus.String("Special Result", variant_level=1))
+ErrorPrompt(service, None, "error")
+VanishPrompt(service, None, "vanish")
+WindowPrompt(service, None, "window")
+
+service.listen() \ No newline at end of file
diff --git a/library/tests/mock/service.py b/library/tests/mock/service.py
index b3f9187..6a49382 100644
--- a/library/tests/mock/service.py
+++ b/library/tests/mock/service.py
@@ -11,9 +11,10 @@
# See the included COPYING file for more information.
#
+import getopt
import os
import sys
-import getopt
+import time
import unittest
import aes
@@ -90,6 +91,48 @@ class AesAlgorithm():
"".join([chr(i) for i in ciph]))
+class SecretPrompt(dbus.service.Object):
+ def __init__(self, service, sender, prompt_name=None, delay=0,
+ dismiss=False, result=dbus.String("", variant_level=1),
+ action=None):
+ self.sender = sender
+ self.service = service
+ self.delay = 0
+ self.dismiss = False
+ self.result = result
+ self.action = action
+ self.completed = False
+ if prompt_name:
+ self.path = "/org/freedesktop/secrets/prompts/%s" % prompt_name
+ else:
+ self.path = "/org/freedesktop/secrets/prompts/p%d" % next_identifier()
+ dbus.service.Object.__init__(self, service.bus_name, self.path)
+ service.add_prompt(self)
+ assert self.path not in objects
+ objects[self.path] = self
+
+ def _complete(self):
+ if self.completed:
+ return
+ self.completed = True
+ self.Completed(self.dismiss, self.result)
+ self.remove_from_connection()
+
+ @dbus.service.method('org.freedesktop.Secret.Prompt')
+ def Prompt(self, window_id):
+ if self.action:
+ self.action()
+ gobject.timeout_add(self.delay * 1000, self._complete)
+
+ @dbus.service.method('org.freedesktop.Secret.Prompt')
+ def Dismiss(self):
+ self._complete()
+
+ @dbus.service.signal(dbus_interface='org.freedesktop.Secret.Prompt', signature='bv')
+ def Completed(self, dismiss, result):
+ pass
+
+
class SecretSession(dbus.service.Object):
def __init__(self, service, sender, algorithm, key):
self.sender = sender
@@ -116,7 +159,7 @@ class SecretSession(dbus.service.Object):
class SecretItem(dbus.service.Object):
def __init__(self, collection, identifier, label="Item", attributes={ },
- secret="", content_type="text/plain"):
+ secret="", confirm=False, content_type="text/plain"):
self.collection = collection
self.identifier = identifier
self.label = label
@@ -125,6 +168,7 @@ class SecretItem(dbus.service.Object):
self.content_type = content_type
self.locked = collection.locked
self.path = "%s/%s" % (collection.path, identifier)
+ self.confirm = confirm
dbus.service.Object.__init__(self, collection.service.bus_name, self.path)
collection.items[identifier] = self
objects[self.path] = self
@@ -135,6 +179,10 @@ class SecretItem(dbus.service.Object):
return False
return True
+ def perform_delete(self):
+ del self.collection.items[self.identifier]
+ del objects[self.path]
+
@dbus.service.method('org.freedesktop.Secret.Item', sender_keyword='sender')
def GetSecret(self, session_path, sender=None):
session = objects.get(session_path, None)
@@ -144,6 +192,16 @@ class SecretItem(dbus.service.Object):
raise IsLocked("secret is locked: %s" % self.path)
return session.encode_secret(self.secret, self.content_type)
+ @dbus.service.method('org.freedesktop.Secret.Item', sender_keyword='sender')
+ def Delete(self, sender=None):
+ if self.confirm:
+ prompt = SecretPrompt(self.collection.service, sender,
+ dismiss=False, action=self.perform_delete)
+ return dbus.ObjectPath(prompt.path)
+ else:
+ self.perform_delete()
+ return dbus.ObjectPath("/")
+
class SecretCollection(dbus.service.Object):
def __init__(self, service, identifier, label="Collection", locked=False):
@@ -179,6 +237,7 @@ class SecretService(dbus.service.Object):
self.bus_name = dbus.service.BusName(name, allow_replacement=True, replace_existing=True)
dbus.service.Object.__init__(self, self.bus_name, '/org/freedesktop/secrets')
self.sessions = { }
+ self.prompts = { }
self.collections = { }
def on_name_owner_changed(owned, old_owner, new_owner):
@@ -213,6 +272,14 @@ class SecretService(dbus.service.Object):
def remove_session(self, session):
self.sessions[session.sender].remove(session)
+ def add_prompt(self, prompt):
+ if prompt.sender not in self.prompts:
+ self.prompts[prompt.sender] = []
+ self.prompts[prompt.sender].append(prompt)
+
+ def remove_prompt (self, prompt):
+ self.prompts[prompt.sender].remove(prompt)
+
def find_item(self, object):
if object.startswith(COLLECTION_PREFIX):
parts = object[len(COLLECTION_PREFIX):].split("/", 1)
@@ -254,6 +321,7 @@ class SecretService(dbus.service.Object):
results[item_path] = item.GetSecret(session_path, sender)
return results
+
def parse_options(args):
global bus_name
try:
diff --git a/library/tests/test-password.c b/library/tests/test-password.c
new file mode 100644
index 0000000..9bad85f
--- /dev/null
+++ b/library/tests/test-password.c
@@ -0,0 +1,137 @@
+/* GSecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2012 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gsecret-password.h"
+#include "gsecret-private.h"
+
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+static gchar *MOCK_NAME = "org.mock.Service";
+
+static const GSecretSchema DELETE_SCHEMA = {
+ "org.mock.schema.Delete",
+ {
+ { "number", GSECRET_ATTRIBUTE_INTEGER },
+ { "string", GSECRET_ATTRIBUTE_STRING },
+ { "even", GSECRET_ATTRIBUTE_BOOLEAN },
+ }
+};
+
+typedef struct {
+ GPid pid;
+} Test;
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ GError *error = NULL;
+ const gchar *mock_script = data;
+ gchar *argv[] = {
+ "python", (gchar *)mock_script,
+ "--name", MOCK_NAME,
+ NULL
+ };
+
+ _gsecret_service_set_default_bus_name (MOCK_NAME);
+
+ g_spawn_async (SRCDIR, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &test->pid, &error);
+ g_assert_no_error (error);
+ g_usleep (200 * 1000);
+}
+
+static void
+teardown (Test *test,
+ gconstpointer unused)
+{
+ g_assert (test->pid);
+ if (kill (test->pid, SIGTERM) < 0)
+ g_error ("kill() failed: %s", g_strerror (errno));
+ g_spawn_close_pid (test->pid);
+}
+
+static void
+on_complete_get_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **ret = user_data;
+ g_assert (ret != NULL);
+ g_assert (*ret == NULL);
+ *ret = g_object_ref (result);
+ egg_test_wait_stop ();
+}
+
+static void
+test_delete_sync (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_password_delete_sync (&DELETE_SCHEMA, NULL, &error,
+ "even", FALSE,
+ "string", "one",
+ "number", 1,
+ NULL);
+
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+}
+
+static void
+test_delete_async (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ gsecret_password_delete (&DELETE_SCHEMA, NULL,
+ on_complete_get_result, &result,
+ "even", FALSE,
+ "string", "one",
+ "number", 1,
+ NULL);
+
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_password_delete_finish (result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_object_unref (result);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-password");
+ g_type_init ();
+
+ g_test_add ("/password/delete-sync", Test, "mock-service-delete.py", setup, test_delete_sync, teardown);
+ g_test_add ("/password/delete-async", Test, "mock-service-delete.py", setup, test_delete_async, teardown);
+
+ return egg_tests_run_with_loop ();
+}
diff --git a/library/tests/test-prompt.c b/library/tests/test-prompt.c
new file mode 100644
index 0000000..c7197cb
--- /dev/null
+++ b/library/tests/test-prompt.c
@@ -0,0 +1,429 @@
+/* GSecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2011 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw@gnome.org>
+ */
+
+
+#include "config.h"
+
+#include "gsecret-item.h"
+#include "gsecret-service.h"
+#include "gsecret-private.h"
+#include "gsecret-prompt.h"
+
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+static gchar *MOCK_NAME = "org.mock.Service";
+
+typedef struct {
+ GPid pid;
+ GDBusConnection *connection;
+ GSecretService *service;
+} Test;
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ GError *error = NULL;
+ const gchar *mock_script = data;
+ gchar *argv[] = {
+ "python", (gchar *)mock_script,
+ "--name", MOCK_NAME,
+ NULL
+ };
+
+ _gsecret_service_set_default_bus_name (MOCK_NAME);
+
+ g_spawn_async (SRCDIR, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &test->pid, &error);
+ g_assert_no_error (error);
+ g_usleep (200 * 1000);
+
+ test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+
+ test->service = _gsecret_service_bare_instance (test->connection, NULL);
+}
+
+static void
+teardown (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+
+ g_object_unref (test->service);
+ egg_assert_not_object (test->service);
+
+ g_assert (test->pid);
+ if (kill (test->pid, SIGTERM) < 0) {
+ if (errno != ESRCH)
+ g_error ("kill() failed: %s", g_strerror (errno));
+ }
+ g_spawn_close_pid (test->pid);
+
+ g_dbus_connection_flush_sync (test->connection, NULL, &error);
+ g_assert_no_error (error);
+ g_object_unref (test->connection);
+}
+
+
+static void
+on_async_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **ret = user_data;
+ g_assert (ret != NULL);
+ g_assert (*ret == NULL);
+ *ret = g_object_ref (result);
+ egg_test_wait_stop ();
+}
+
+static gboolean
+on_idle_increment (gpointer user_data)
+{
+ guint *value = user_data;
+ ++(*value);
+ return TRUE;
+}
+
+static void
+test_perform_sync (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+ guint value = 0;
+ guint increment_id;
+
+ /* Verify that main loop does not run during this call */
+ increment_id = g_idle_add (on_idle_increment, &value);
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple");
+
+ ret = gsecret_prompt_perform_sync (prompt, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_assert_cmpuint (value, ==, 0);
+ g_source_remove (increment_id);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_perform_run (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+ guint value = 0;
+ guint increment_id;
+
+ /* Verify that main loop does run during this call */
+ increment_id = g_idle_add (on_idle_increment, &value);
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple");
+
+ ret = gsecret_prompt_run (prompt, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ g_assert_cmpuint (value, >, 0);
+ g_source_remove (increment_id);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_perform_async (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple");
+
+ gsecret_prompt_perform (prompt, 0, NULL, on_async_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_prompt_perform_finish (prompt, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+ g_object_unref (result);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_perform_cancel (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ GCancellable *cancellable;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/delay");
+
+ cancellable = g_cancellable_new ();
+ gsecret_prompt_perform (prompt, 0, cancellable, on_async_result, &result);
+ g_assert (result == NULL);
+
+ g_cancellable_cancel (cancellable);
+ g_object_unref (cancellable);
+
+ egg_test_wait ();
+
+ ret = gsecret_prompt_perform_finish (prompt, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_object_unref (result);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_perform_fail (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/error");
+
+ ret = gsecret_prompt_perform_sync (prompt, 0, NULL, &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED);
+ g_assert (ret == FALSE);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_perform_vanish (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/vanish");
+
+ ret = gsecret_prompt_perform_sync (prompt, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == FALSE);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_prompt_result (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+ GVariant *result;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/result");
+
+ result = gsecret_prompt_get_result_value (prompt);
+ g_assert (result == NULL);
+
+ ret = gsecret_prompt_perform_sync (prompt, 0, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ result = gsecret_prompt_get_result_value (prompt);
+ g_assert (result != NULL);
+ g_assert_cmpstr (g_variant_get_type_string (result), ==, "s");
+ g_assert_cmpstr (g_variant_get_string (result, NULL), ==, "Special Result");
+ g_variant_unref (result);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_prompt_window_id (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+ GVariant *result;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/window");
+
+ ret = gsecret_prompt_perform_sync (prompt, 555, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ result = gsecret_prompt_get_result_value (prompt);
+ g_assert (result != NULL);
+ g_assert_cmpstr (g_variant_get_type_string (result), ==, "s");
+ g_assert_cmpstr (g_variant_get_string (result, NULL), ==, "555");
+ g_variant_unref (result);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_service_sync (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple");
+
+ ret = gsecret_service_prompt_sync (test->service, prompt, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_service_async (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/simple");
+
+ gsecret_service_prompt (test->service, prompt, NULL, on_async_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_service_prompt_finish (test->service, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+ g_object_unref (result);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_service_fail (Test *test,
+ gconstpointer unused)
+{
+ GSecretPrompt *prompt;
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/error");
+
+ gsecret_service_prompt (test->service, prompt, NULL, on_async_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_service_prompt_finish (test->service, result, &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED);
+ g_assert (ret == FALSE);
+ g_object_unref (result);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+
+ g_object_unref (prompt);
+ egg_assert_not_object (prompt);
+}
+
+static void
+test_service_path (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ gsecret_service_prompt_path (test->service, "/org/freedesktop/secrets/prompts/simple",
+ NULL, on_async_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_service_prompt_finish (test->service, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+ g_object_unref (result);
+
+ /* Make sure everything completes */
+ egg_test_wait_idle ();
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+ g_set_prgname ("test-prompt");
+ g_type_init ();
+
+ g_test_add ("/prompt/run", Test, "mock-service-prompt.py", setup, test_perform_run, teardown);
+ g_test_add ("/prompt/perform-sync", Test, "mock-service-prompt.py", setup, test_perform_sync, teardown);
+ g_test_add ("/prompt/perform-async", Test, "mock-service-prompt.py", setup, test_perform_async, teardown);
+ g_test_add ("/prompt/perform-cancel", Test, "mock-service-prompt.py", setup, test_perform_cancel, teardown);
+ g_test_add ("/prompt/perform-fail", Test, "mock-service-prompt.py", setup, test_perform_fail, teardown);
+ g_test_add ("/prompt/perform-vanish", Test, "mock-service-prompt.py", setup, test_perform_vanish, teardown);
+ g_test_add ("/prompt/result", Test, "mock-service-prompt.py", setup, test_prompt_result, teardown);
+ g_test_add ("/prompt/window-id", Test, "mock-service-prompt.py", setup, test_prompt_window_id, teardown);
+
+ g_test_add ("/prompt/service-sync", Test, "mock-service-prompt.py", setup, test_service_sync, teardown);
+ g_test_add ("/prompt/service-async", Test, "mock-service-prompt.py", setup, test_service_async, teardown);
+ g_test_add ("/prompt/service-path", Test, "mock-service-prompt.py", setup, test_service_path, teardown);
+ g_test_add ("/prompt/service-fail", Test, "mock-service-prompt.py", setup, test_service_fail, teardown);
+
+ return egg_tests_run_with_loop ();
+}
diff --git a/library/tests/test-service.c b/library/tests/test-service.c
index 50fbbd0..b7e59c6 100644
--- a/library/tests/test-service.c
+++ b/library/tests/test-service.c
@@ -25,6 +25,15 @@
static gchar *MOCK_NAME = "org.mock.Service";
+static const GSecretSchema DELETE_SCHEMA = {
+ "org.mock.schema.Delete",
+ {
+ { "number", GSECRET_ATTRIBUTE_INTEGER },
+ { "string", GSECRET_ATTRIBUTE_STRING },
+ { "even", GSECRET_ATTRIBUTE_BOOLEAN },
+ }
+};
+
typedef struct {
GPid pid;
GDBusConnection *connection;
@@ -32,8 +41,8 @@ typedef struct {
} Test;
static void
-setup (Test *test,
- gconstpointer data)
+setup_mock (Test *test,
+ gconstpointer data)
{
GError *error = NULL;
const gchar *mock_script = data;
@@ -43,29 +52,49 @@ setup (Test *test,
NULL
};
+ _gsecret_service_set_default_bus_name (MOCK_NAME);
+
g_spawn_async (SRCDIR, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &test->pid, &error);
g_assert_no_error (error);
g_usleep (200 * 1000);
+}
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ GError *error = NULL;
+
+ setup_mock (test, data);
test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
- test->service = _gsecret_service_bare_instance (test->connection, MOCK_NAME);
+ test->service = _gsecret_service_bare_instance (test->connection, NULL);
+}
+
+static void
+teardown_mock (Test *test,
+ gconstpointer unused)
+{
+ g_assert (test->pid);
+ if (kill (test->pid, SIGTERM) < 0)
+ g_error ("kill() failed: %s", g_strerror (errno));
+ g_spawn_close_pid (test->pid);
}
static void
teardown (Test *test,
gconstpointer unused)
{
+ egg_test_wait_idle ();
+
g_object_unref (test->service);
egg_assert_not_object (test->service);
g_clear_object (&test->connection);
- g_assert (test->pid);
- if (kill (test->pid, SIGTERM) < 0)
- g_error ("kill() failed: %s", g_strerror (errno));
- g_spawn_close_pid (test->pid);
+ teardown_mock (test, unused);
}
static void
@@ -117,6 +146,60 @@ test_instance (void)
}
static void
+test_connect_sync (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ GSecretService *service;
+ const gchar *path;
+
+ /* Passing false, not session */
+ _gsecret_service_bare_connect (MOCK_NAME, FALSE, NULL, on_complete_get_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ service = _gsecret_service_bare_connect_finish (result, &error);
+ g_assert (GSECRET_IS_SERVICE (service));
+ g_assert_no_error (error);
+ g_object_unref (result);
+
+ path = gsecret_service_get_session_path (service);
+ g_assert (path == NULL);
+
+ g_object_unref (service);
+ egg_assert_not_object (service);
+}
+
+static void
+test_connect_ensure_sync (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ GSecretService *service;
+ const gchar *path;
+
+ /* Passing true, ensures session is established */
+ _gsecret_service_bare_connect (MOCK_NAME, TRUE, NULL, on_complete_get_result, &result);
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ service = _gsecret_service_bare_connect_finish (result, &error);
+ g_assert_no_error (error);
+ g_assert (GSECRET_IS_SERVICE (service));
+ g_object_unref (result);
+
+ path = gsecret_service_get_session_path (service);
+ g_assert (path != NULL);
+
+ g_object_unref (service);
+ egg_assert_not_object (service);
+}
+
+static void
test_search_paths (Test *test,
gconstpointer used)
{
@@ -405,6 +488,111 @@ test_secrets_for_paths_async (Test *test,
g_hash_table_unref (values);
}
+static void
+test_delete_for_path_sync (Test *test,
+ gconstpointer used)
+
+{
+ const gchar *path_item_one = "/org/freedesktop/secrets/collection/to_delete/item";
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_service_delete_path_sync (test->service, path_item_one, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+}
+
+static void
+test_delete_for_path_sync_prompt (Test *test,
+ gconstpointer used)
+
+{
+ const gchar *path_item_one = "/org/freedesktop/secrets/collection/to_delete/confirm";
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_service_delete_path_sync (test->service, path_item_one, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+}
+
+static void
+test_delete_password_sync (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_service_delete_password_sync (test->service, &DELETE_SCHEMA, NULL, &error,
+ "even", FALSE,
+ "string", "one",
+ "number", 1,
+ NULL);
+
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+}
+
+static void
+test_delete_password_async (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ GAsyncResult *result = NULL;
+ gboolean ret;
+
+ gsecret_service_delete_password (test->service, &DELETE_SCHEMA, NULL,
+ on_complete_get_result, &result,
+ "even", FALSE,
+ "string", "one",
+ "number", 1,
+ NULL);
+
+ g_assert (result == NULL);
+
+ egg_test_wait ();
+
+ ret = gsecret_service_delete_password_finish (test->service, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+
+ g_object_unref (result);
+}
+
+static void
+test_delete_password_locked (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ gboolean ret;
+
+ ret = gsecret_service_delete_password_sync (test->service, &DELETE_SCHEMA, NULL, &error,
+ "even", FALSE,
+ "string", "three",
+ "number", 3,
+ NULL);
+
+ g_assert_no_error (error);
+ g_assert (ret == TRUE);
+}
+
+static void
+test_delete_password_no_match (Test *test,
+ gconstpointer used)
+{
+ GError *error = NULL;
+ gboolean ret;
+
+ /* Won't match anything */
+ ret = gsecret_service_delete_password_sync (test->service, &DELETE_SCHEMA, NULL, &error,
+ "even", TRUE,
+ "string", "one",
+ NULL);
+
+ g_assert_no_error (error);
+ g_assert (ret == FALSE);
+}
+
int
main (int argc, char **argv)
{
@@ -413,14 +601,26 @@ main (int argc, char **argv)
g_type_init ();
g_test_add_func ("/service/instance", test_instance);
+
+ g_test_add ("/service/connect-sync", Test, "mock-service-normal.py", setup_mock, test_connect_sync, teardown_mock);
+ g_test_add ("/service/connect-ensure-sync", Test, "mock-service-normal.py", setup_mock, test_connect_ensure_sync, teardown_mock);
+
g_test_add ("/service/search-for-paths", Test, "mock-service-normal.py", setup, test_search_paths, teardown);
g_test_add ("/service/search-for-paths-async", Test, "mock-service-normal.py", setup, test_search_paths_async, teardown);
g_test_add ("/service/search-for-paths-nulls", Test, "mock-service-normal.py", setup, test_search_paths_nulls, teardown);
+
g_test_add ("/service/secret-for-path", Test, "mock-service-normal.py", setup, test_secret_for_path, teardown);
g_test_add ("/service/secret-for-path-plain", Test, "mock-service-only-plain.py", setup, test_secret_for_path, teardown);
g_test_add ("/service/secret-for-path-async", Test, "mock-service-normal.py", setup, test_secret_for_path_async, teardown);
g_test_add ("/service/secrets-for-paths", Test, "mock-service-normal.py", setup, test_secrets_for_paths, teardown);
g_test_add ("/service/secrets-for-paths-async", Test, "mock-service-normal.py", setup, test_secrets_for_paths_async, teardown);
+ g_test_add ("/service/delete-for-path", Test, "mock-service-delete.py", setup, test_delete_for_path_sync, teardown);
+ g_test_add ("/service/delete-for-path-with-prompt", Test, "mock-service-delete.py", setup, test_delete_for_path_sync_prompt, teardown);
+ g_test_add ("/service/delete-password-sync", Test, "mock-service-delete.py", setup, test_delete_password_sync, teardown);
+ g_test_add ("/service/delete-password-async", Test, "mock-service-delete.py", setup, test_delete_password_async, teardown);
+ g_test_add ("/service/delete-password-locked", Test, "mock-service-delete.py", setup, test_delete_password_locked, teardown);
+ g_test_add ("/service/delete-password-no-match", Test, "mock-service-delete.py", setup, test_delete_password_no_match, teardown);
+
return egg_tests_run_with_loop ();
}
diff --git a/library/tests/test-session.c b/library/tests/test-session.c
index 5611939..98df7be 100644
--- a/library/tests/test-session.c
+++ b/library/tests/test-session.c
@@ -44,6 +44,8 @@ setup (Test *test,
NULL
};
+ _gsecret_service_set_default_bus_name (MOCK_NAME);
+
g_spawn_async (SRCDIR, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &test->pid, &error);
g_assert_no_error (error);
g_usleep (200 * 1000);
@@ -51,7 +53,7 @@ setup (Test *test,
test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
- test->service = _gsecret_service_bare_instance (test->connection, MOCK_NAME);
+ test->service = _gsecret_service_bare_instance (test->connection, NULL);
}
static void