[gnome-keyring] daemon: Emit secret service signals when collections/items change
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring] daemon: Emit secret service signals when collections/items change
- Date: Wed, 27 Jun 2012 09:42:43 +0000 (UTC)
commit 8ce8788e850357a1467e6f18ca952248888da116
Author: Stef Walter <stefw gnome org>
Date: Wed Jun 27 11:38:29 2012 +0200
daemon: Emit secret service signals when collections/items change
* Emit the Secret Service DBus API signals when collections/items
change.
* Also fire the PropertiesChanged signal appropriately
.gitignore | 2 +
daemon/dbus/gkd-secret-create.c | 6 +-
daemon/dbus/gkd-secret-objects.c | 391 ++++++++++++--
daemon/dbus/gkd-secret-objects.h | 19 +
daemon/dbus/gkd-secret-service.c | 116 ++++-
daemon/dbus/gkd-secret-service.h | 6 +
daemon/dbus/gkd-secret-unlock.c | 16 +
daemon/dbus/tests/Makefile.am | 13 +-
daemon/dbus/tests/files/test.keyring | Bin 0 -> 180 bytes
daemon/dbus/tests/test-secret-signals.c | 916 +++++++++++++++++++++++++++++++
10 files changed, 1432 insertions(+), 53 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index eecb8d1..a6e8721 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,6 +104,8 @@ p11-tests.conf
/daemon/control/tests/frob-control-quit
/daemon/control/tests/frob-control-unlock
+/daemon/dbus/tests/test-secret-signals
+
/pkcs11/gkm/tests/test-attributes
/pkcs11/gkm/tests/test-certificate
/pkcs11/gkm/tests/test-credential
diff --git a/daemon/dbus/gkd-secret-create.c b/daemon/dbus/gkd-secret-create.c
index d59b319..a3aeae4 100644
--- a/daemon/dbus/gkd-secret-create.c
+++ b/daemon/dbus/gkd-secret-create.c
@@ -117,14 +117,18 @@ create_collection_with_secret (GkdSecretCreate *self, GkdSecretSecret *master)
return FALSE;
}
+ service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self));
+
if (self->alias) {
if (!gkd_secret_util_parse_path (self->result_path, &identifier, NULL))
g_assert_not_reached ();
- service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self));
gkd_secret_service_set_alias (service, self->alias, identifier);
g_free (identifier);
}
+ /* Notify the callers that a collection was created */
+ gkd_secret_service_emit_collection_created (service, self->result_path);
+
return TRUE;
}
diff --git a/daemon/dbus/gkd-secret-objects.c b/daemon/dbus/gkd-secret-objects.c
index 491d130..8bc500f 100644
--- a/daemon/dbus/gkd-secret-objects.c
+++ b/daemon/dbus/gkd-secret-objects.c
@@ -51,6 +51,13 @@ struct _GkdSecretObjects {
GckSlot *pkcs11_slot;
};
+static gchar * object_path_for_item (const gchar *base,
+ GckObject *item);
+
+static gchar * object_path_for_collection (GckObject *collection);
+
+static gchar * collection_path_for_item (GckObject *item);
+
G_DEFINE_TYPE (GkdSecretObjects, gkd_secret_objects, G_TYPE_OBJECT);
/* -----------------------------------------------------------------------------
@@ -122,8 +129,10 @@ object_property_get (GckObject *object, DBusMessage *message,
}
static DBusMessage*
-object_property_set (GckObject *object, DBusMessage *message,
- DBusMessageIter *iter, const gchar *prop_name)
+object_property_set (GckObject *object,
+ DBusMessage *message,
+ DBusMessageIter *iter,
+ const gchar *prop_name)
{
GckBuilder builder = GCK_BUILDER_INIT;
DBusMessage *reply;
@@ -180,11 +189,14 @@ item_property_get (GckObject *object, DBusMessage *message)
}
static DBusMessage*
-item_property_set (GckObject *object, DBusMessage *message)
+item_property_set (GkdSecretObjects *self,
+ GckObject *object,
+ DBusMessage *message)
{
DBusMessageIter iter;
const char *interface;
const char *name;
+ DBusMessage *reply;
if (!dbus_message_has_signature (message, "ssv"))
return NULL;
@@ -200,7 +212,13 @@ item_property_set (GckObject *object, DBusMessage *message)
"Object does not have properties on interface '%s'",
interface);
- return object_property_set (object, message, &iter, name);
+ reply = object_property_set (object, message, &iter, name);
+
+ /* Notify everyone a property changed */
+ if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ gkd_secret_objects_emit_item_changed (self, object, name, NULL);
+
+ return reply;
}
static DBusMessage*
@@ -248,13 +266,30 @@ static DBusMessage*
item_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
{
GError *error = NULL;
+ gchar *collection_path;
+ gchar *item_path;
DBusMessage *reply;
const gchar *prompt;
+ GckObject *collection;
if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
return NULL;
- if (!gck_object_destroy (object, NULL, &error)) {
+ collection_path = collection_path_for_item (object);
+ item_path = object_path_for_item (NULL, object);
+
+ if (gck_object_destroy (object, NULL, &error)) {
+ collection = gkd_secret_objects_lookup_collection (self, NULL, collection_path);
+ if (collection != NULL) {
+ gkd_secret_objects_emit_item_deleted (self, collection, item_path);
+ g_object_unref (collection);
+ }
+
+ prompt = "/"; /* No prompt necessary */
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
+
+ } else {
if (g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
reply = dbus_message_new_error_printf (message, SECRET_ERROR_IS_LOCKED,
"Cannot delete a locked item");
@@ -262,13 +297,12 @@ item_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage *mess
reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
"Couldn't delete collection: %s",
egg_error_message (error));
+
g_clear_error (&error);
- return reply;
}
- prompt = "/"; /* No prompt necessary */
- reply = dbus_message_new_method_return (message);
- dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
+ g_free (collection_path);
+ g_free (item_path);
return reply;
}
@@ -348,7 +382,7 @@ item_message_handler (GkdSecretObjects *self, GckObject *object, DBusMessage *me
/* org.freedesktop.DBus.Properties.Set */
else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set"))
- return item_property_set (object, message);
+ return item_property_set (self, object, message);
/* org.freedesktop.DBus.Properties.GetAll */
else if (dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "GetAll"))
@@ -424,6 +458,7 @@ static DBusMessage*
collection_property_set (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
{
DBusMessageIter iter;
+ DBusMessage *reply;
const char *interface;
const char *name;
@@ -441,7 +476,13 @@ collection_property_set (GkdSecretObjects *self, GckObject *object, DBusMessage
"Object does not have properties on interface '%s'",
interface);
- return object_property_set (object, message, &iter, name);
+ reply = object_property_set (object, message, &iter, name);
+
+ /* Notify everyone a property changed */
+ if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ gkd_secret_objects_emit_collection_changed (self, object, name, NULL);
+
+ return reply;
}
static DBusMessage*
@@ -543,7 +584,7 @@ collection_find_matching_item (GkdSecretObjects *self,
static gchar *
object_path_for_item (const gchar *base,
- GckObject *object)
+ GckObject *item)
{
GError *error = NULL;
gpointer identifier;
@@ -551,19 +592,10 @@ object_path_for_item (const gchar *base,
gchar *alloc = NULL;
gchar *path = NULL;
- if (base == NULL) {
- identifier = gck_object_get_data (object, CKA_G_COLLECTION, NULL, &n_identifier, &error);
- if (!identifier) {
- g_warning ("couldn't get item collection identifier: %s", egg_error_message (error));
- g_clear_error (&error);
- return NULL;
- }
-
- base = alloc = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
- g_free (identifier);
- }
+ if (base == NULL)
+ base = alloc = collection_path_for_item (item);
- identifier = gck_object_get_data (object, CKA_ID, NULL, &n_identifier, &error);
+ identifier = gck_object_get_data (item, CKA_ID, NULL, &n_identifier, &error);
if (identifier == NULL) {
g_warning ("couldn't get item identifier: %s", egg_error_message (error));
g_clear_error (&error);
@@ -578,6 +610,48 @@ object_path_for_item (const gchar *base,
return path;
}
+static gchar *
+collection_path_for_item (GckObject *item)
+{
+ GError *error = NULL;
+ gpointer identifier;
+ gsize n_identifier;
+ gchar *path = NULL;
+
+ identifier = gck_object_get_data (item, CKA_G_COLLECTION, NULL, &n_identifier, &error);
+ if (!identifier) {
+ g_warning ("couldn't get item collection identifier: %s", egg_error_message (error));
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
+ g_free (identifier);
+ return path;
+}
+
+static gchar *
+object_path_for_collection (GckObject *collection)
+{
+ GError *error = NULL;
+ gpointer identifier;
+ gsize n_identifier;
+ gchar *path = NULL;
+
+ identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, &error);
+ if (identifier == NULL) {
+ g_warning ("couldn't get collection identifier: %s", egg_error_message (error));
+ g_clear_error (&error);
+ path = NULL;
+
+ } else {
+ path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
+ g_free (identifier);
+ }
+
+ return path;
+}
+
static DBusMessage*
collection_method_create_item (GkdSecretObjects *self, GckObject *object, DBusMessage *message)
{
@@ -657,10 +731,12 @@ collection_method_create_item (GkdSecretObjects *self, GckObject *object, DBusMe
goto cleanup;
}
+ path = object_path_for_item (base, item);
+ gkd_secret_objects_emit_item_created (self, object, item);
+
/* Build up the item identifier */
reply = dbus_message_new_method_return (message);
dbus_message_iter_init_append (reply, &iter);
- path = object_path_for_item (base, item);
dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &path);
prompt = "/";
dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &prompt);
@@ -701,18 +777,27 @@ collection_method_delete (GkdSecretObjects *self, GckObject *object, DBusMessage
GError *error = NULL;
DBusMessage *reply;
const gchar *prompt;
+ gchar *path;
if (!dbus_message_get_args (message, NULL, DBUS_TYPE_INVALID))
return NULL;
+ path = object_path_for_collection (object);
+ g_return_val_if_fail (path != NULL, NULL);
+
if (!gck_object_destroy (object, NULL, &error)) {
reply = dbus_message_new_error_printf (message, DBUS_ERROR_FAILED,
"Couldn't delete collection: %s",
egg_error_message (error));
g_clear_error (&error);
+ g_free (path);
return reply;
}
+ /* Notify the callers that a collection was deleted */
+ gkd_secret_service_emit_collection_deleted (self->service, path);
+ g_free (path);
+
prompt = "/";
reply = dbus_message_new_method_return (message);
dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &prompt, DBUS_TYPE_INVALID);
@@ -981,14 +1066,16 @@ gkd_secret_objects_lookup_collection (GkdSecretObjects *self, const gchar *calle
gchar *identifier;
g_return_val_if_fail (GKD_SECRET_IS_OBJECTS (self), NULL);
- g_return_val_if_fail (caller, NULL);
g_return_val_if_fail (path, NULL);
if (!parse_object_path (self, path, &identifier, NULL))
return NULL;
/* The session we're using to access the object */
- session = gkd_secret_service_get_pkcs11_session (self->service, caller);
+ if (caller == NULL)
+ session = gkd_secret_service_internal_pkcs11_session (self->service);
+ else
+ session = gkd_secret_service_get_pkcs11_session (self->service, caller);
g_return_val_if_fail (session, NULL);
gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
@@ -1089,8 +1176,12 @@ gkd_secret_objects_foreach_item (GkdSecretObjects *self,
g_return_if_fail (callback != NULL);
/* The session we're using to access the object */
- session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
- g_return_if_fail (session);
+ if (message == NULL) {
+ session = gkd_secret_service_internal_pkcs11_session (self->service);
+ } else {
+ session = gkd_secret_service_get_pkcs11_session (self->service,
+ dbus_message_get_sender (message));
+ }
if (!parse_object_path (self, base, &identifier, NULL))
g_return_if_reached ();
@@ -1134,7 +1225,6 @@ gkd_secret_objects_append_item_paths (GkdSecretObjects *self,
g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
g_return_if_fail (base);
g_return_if_fail (iter);
- g_return_if_fail (message);
dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
@@ -1164,8 +1254,12 @@ gkd_secret_objects_foreach_collection (GkdSecretObjects *self,
g_return_if_fail (callback);
/* The session we're using to access the object */
- session = gkd_secret_service_get_pkcs11_session (self->service, dbus_message_get_sender (message));
- g_return_if_fail (session);
+ if (message == NULL) {
+ session = gkd_secret_service_internal_pkcs11_session (self->service);
+ } else {
+ session = gkd_secret_service_get_pkcs11_session (self->service,
+ dbus_message_get_sender (message));
+ }
gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
@@ -1205,7 +1299,7 @@ gkd_secret_objects_append_collection_paths (GkdSecretObjects *self,
DBusMessageIter array;
g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
- g_return_if_fail (iter && message);
+ g_return_if_fail (iter != NULL);
dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, "ao", &variant);
dbus_message_iter_open_container (&variant, DBUS_TYPE_ARRAY, "o", &array);
@@ -1380,3 +1474,234 @@ gkd_secret_objects_handle_get_secrets (GkdSecretObjects *self, DBusMessage *mess
return reply;
}
+
+static void
+on_each_item_emit_locked (GkdSecretObjects *self,
+ const gchar *path,
+ GckObject *object,
+ gpointer user_data)
+{
+ gkd_secret_objects_emit_item_changed (self, object, "Locked", NULL);
+}
+
+void
+gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
+ GckObject *collection)
+{
+ const gchar *collection_path;
+
+ collection_path = object_path_for_collection (collection);
+ gkd_secret_objects_foreach_item (self, NULL, collection_path,
+ on_each_item_emit_locked, NULL);
+
+ gkd_secret_objects_emit_collection_changed (self, collection, "Locked", NULL);
+}
+
+static void
+emit_object_properties_changed (GkdSecretObjects *self,
+ GckObject *object,
+ const gchar *path,
+ const gchar *iface,
+ va_list va)
+{
+ gchar *collection_path;
+ const gchar *propname;
+ DBusMessage *message;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ CK_ATTRIBUTE_TYPE type;
+ GckAttributes *attrs;
+ GError *error = NULL;
+ gboolean items = FALSE;
+ GArray *types;
+
+ types = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE_TYPE));
+ while ((propname = va_arg (va, const gchar *)) != NULL) {
+
+ /* Special case the Items property */
+ if (g_str_equal (propname, "Items")) {
+ items = TRUE;
+ continue;
+ }
+
+ if (gkd_secret_property_get_type (propname, &type))
+ g_array_append_val (types, type);
+ else
+ g_warning ("invalid property: %s", propname);
+ }
+
+ attrs = gck_object_get_full (object, (CK_ATTRIBUTE_TYPE *)types->data,
+ types->len, NULL, &error);
+ g_array_free (types, TRUE);
+
+ if (error != NULL) {
+ g_warning ("couldn't retrieve properties: %s", egg_error_message (error));
+ return;
+ }
+
+ message = dbus_message_new_signal (path, DBUS_INTERFACE_PROPERTIES,
+ "PropertiesChanged");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+ gkd_secret_property_append_all (&array, attrs);
+
+ /* Append the Items property */
+ if (items) {
+ collection_path = object_path_for_collection (object);
+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ propname = "Items";
+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &propname);
+ gkd_secret_objects_append_item_paths (self, collection_path, &dict, NULL);
+ dbus_message_iter_close_container (&array, &dict);
+ g_free (collection_path);
+ }
+
+ dbus_message_iter_close_container (&iter, &array);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
+ dbus_message_iter_close_container (&iter, &array);
+
+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
+ message, NULL))
+ g_return_if_reached ();
+ dbus_message_unref (message);
+
+ gck_attributes_unref (attrs);
+}
+
+void
+gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
+ GckObject *collection,
+ ...)
+{
+ DBusMessage *message;
+ gchar *collection_path;
+ va_list va;
+
+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
+ g_return_if_fail (GCK_OBJECT (collection));
+
+ collection_path = object_path_for_collection (collection);
+
+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "CollectionChanged");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
+ message, NULL))
+ g_return_if_reached ();
+
+ dbus_message_unref (message);
+
+ va_start (va, collection);
+ emit_object_properties_changed (self, collection, collection_path,
+ SECRET_COLLECTION_INTERFACE, va);
+ va_end (va);
+
+ g_free (collection_path);
+}
+
+void
+gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
+ GckObject *collection,
+ GckObject *item)
+{
+ DBusMessage *message;
+ gchar *collection_path;
+ gchar *item_path;
+
+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
+ g_return_if_fail (GCK_OBJECT (collection));
+ g_return_if_fail (GCK_OBJECT (item));
+
+ collection_path = object_path_for_collection (collection);
+ item_path = object_path_for_item (collection_path, item);
+
+ message = dbus_message_new_signal (collection_path,
+ SECRET_COLLECTION_INTERFACE,
+ "ItemCreated");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
+ message, NULL))
+ g_return_if_reached ();
+
+ dbus_message_unref (message);
+
+ gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
+
+ g_free (item_path);
+ g_free (collection_path);
+}
+
+void
+gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
+ GckObject *item,
+ ...)
+{
+ DBusMessage *message;
+ gchar *collection_path;
+ gchar *item_path;
+ va_list va;
+
+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
+ g_return_if_fail (GCK_OBJECT (item));
+
+ collection_path = collection_path_for_item (item);
+ item_path = object_path_for_item (collection_path, item);
+
+ message = dbus_message_new_signal (collection_path,
+ SECRET_COLLECTION_INTERFACE,
+ "ItemChanged");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
+ message, NULL))
+ g_return_if_reached ();
+
+ dbus_message_unref (message);
+
+ va_start (va, item);
+ emit_object_properties_changed (self, item, item_path,
+ SECRET_ITEM_INTERFACE, va);
+ va_end (va);
+
+ g_free (item_path);
+ g_free (collection_path);
+}
+
+void
+gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
+ GckObject *collection,
+ const gchar *item_path)
+{
+ DBusMessage *message;
+ gchar *collection_path;
+
+ g_return_if_fail (GKD_SECRET_IS_OBJECTS (self));
+ g_return_if_fail (GCK_OBJECT (collection));
+ g_return_if_fail (item_path != NULL);
+
+ collection_path = object_path_for_collection (collection);
+
+ message = dbus_message_new_signal (collection_path,
+ SECRET_COLLECTION_INTERFACE,
+ "ItemDeleted");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &item_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (gkd_secret_service_get_connection (self->service),
+ message, NULL))
+ g_return_if_reached ();
+
+ dbus_message_unref (message);
+ g_free (collection_path);
+
+ gkd_secret_objects_emit_collection_changed (self, collection, "Items", NULL);
+}
diff --git a/daemon/dbus/gkd-secret-objects.h b/daemon/dbus/gkd-secret-objects.h
index 234efd3..bd7f1aa 100644
--- a/daemon/dbus/gkd-secret-objects.h
+++ b/daemon/dbus/gkd-secret-objects.h
@@ -90,4 +90,23 @@ GckObject* gkd_secret_objects_lookup_item (GkdSecretObjec
const gchar *caller,
const gchar *path);
+void gkd_secret_objects_emit_collection_locked (GkdSecretObjects *self,
+ GckObject *collection);
+
+void gkd_secret_objects_emit_collection_changed (GkdSecretObjects *self,
+ GckObject *collection,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gkd_secret_objects_emit_item_created (GkdSecretObjects *self,
+ GckObject *collection,
+ GckObject *item);
+
+void gkd_secret_objects_emit_item_changed (GkdSecretObjects *self,
+ GckObject *item,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void gkd_secret_objects_emit_item_deleted (GkdSecretObjects *self,
+ GckObject *collection,
+ const gchar *item_path);
+
#endif /* __GKD_SECRET_OBJECTS_H__ */
diff --git a/daemon/dbus/gkd-secret-service.c b/daemon/dbus/gkd-secret-service.c
index de57446..4aa166e 100644
--- a/daemon/dbus/gkd-secret-service.c
+++ b/daemon/dbus/gkd-secret-service.c
@@ -334,15 +334,31 @@ service_property_set (GkdSecretService *self, DBusMessage *message)
return NULL; /* TODO: Need to implement */
}
+static void
+service_append_all_properties (GkdSecretService *self,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ const gchar *name;
+
+ dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+
+ name = "Collections";
+ dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
+ gkd_secret_objects_append_collection_paths (self->objects, &dict, NULL);
+ dbus_message_iter_close_container (&array, &dict);
+
+ dbus_message_iter_close_container (iter, &array);
+}
+
static DBusMessage*
service_property_getall (GkdSecretService *self, DBusMessage *message)
{
DBusMessage *reply = NULL;
- DBusMessageIter array;
- DBusMessageIter dict;
DBusMessageIter iter;
const gchar *interface;
- const gchar *name;
if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
return NULL;
@@ -354,16 +370,7 @@ service_property_getall (GkdSecretService *self, DBusMessage *message)
reply = dbus_message_new_method_return (message);
dbus_message_iter_init_append (reply, &iter);
- dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &array);
-
- name = "Collections";
- dbus_message_iter_open_container (&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
- dbus_message_iter_append_basic (&dict, DBUS_TYPE_STRING, &name);
- gkd_secret_objects_append_collection_paths (self->objects, &dict, message);
- dbus_message_iter_close_container (&array, &dict);
-
- dbus_message_iter_close_container (&iter, &array);
-
+ service_append_all_properties (self, &iter);
return reply;
}
@@ -529,8 +536,11 @@ service_method_lock (GkdSecretService *self, DBusMessage *message)
for (i = 0; i < n_objpaths; ++i) {
collection = gkd_secret_objects_lookup_collection (self->objects, caller, objpaths[i]);
if (collection != NULL) {
- if (gkd_secret_lock (collection, NULL))
+ if (gkd_secret_lock (collection, NULL)) {
g_ptr_array_add (array, objpaths[i]);
+ gkd_secret_objects_emit_collection_locked (self->objects,
+ collection);
+ }
g_object_unref (collection);
}
}
@@ -700,6 +710,9 @@ service_method_create_with_master_password (GkdSecretService *self, DBusMessage
if (path == NULL)
return gkd_secret_propagate_error (message, "Couldn't create collection", error);
+ /* Notify the callers that a collection was created */
+ gkd_secret_service_emit_collection_created (self, path);
+
reply = dbus_message_new_method_return (message);
dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID);
g_free (path);
@@ -790,17 +803,19 @@ service_method_unlock_with_master_password (GkdSecretService *self, DBusMessage
path);
/* No such collection */
- if (collection == NULL)
+ if (collection == NULL) {
reply = dbus_message_new_error (message, SECRET_ERROR_NO_SUCH_OBJECT,
"The collection does not exist");
/* Success */
- else if (gkd_secret_unlock_with_secret (collection, master, &error))
+ } else if (gkd_secret_unlock_with_secret (collection, master, &error)) {
reply = dbus_message_new_method_return (message);
+ gkd_secret_objects_emit_collection_locked (self->objects, collection);
/* Failure */
- else
+ } else {
reply = gkd_secret_propagate_error (message, "Couldn't unlock collection", error);
+ }
gkd_secret_secret_free (master);
@@ -1469,3 +1484,70 @@ gkd_secret_service_publish_dispatch (GkdSecretService *self, const gchar *caller
g_return_if_fail (!g_hash_table_lookup (client->dispatch, path));
g_hash_table_replace (client->dispatch, (gpointer)path, g_object_ref (object));
}
+
+static void
+emit_collections_properties_changed (GkdSecretService *self)
+{
+ const gchar *iface = SECRET_SERVICE_INTERFACE;
+ DBusMessage *message;
+ DBusMessageIter array;
+ DBusMessageIter iter;
+
+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
+ DBUS_INTERFACE_PROPERTIES,
+ "PropertiesChanged");
+
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface);
+ service_append_all_properties (self, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &array);
+ dbus_message_iter_close_container (&iter, &array);
+
+ if (!dbus_connection_send (self->connection, message, NULL))
+ g_return_if_reached ();
+ dbus_message_unref (message);
+}
+
+void
+gkd_secret_service_emit_collection_created (GkdSecretService *self,
+ const gchar *collection_path)
+{
+ DBusMessage *message;
+
+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
+ g_return_if_fail (collection_path != NULL);
+
+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "CollectionCreated");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (self->connection, message, NULL))
+ g_return_if_reached ();
+ dbus_message_unref (message);
+
+ emit_collections_properties_changed (self);
+}
+
+void
+gkd_secret_service_emit_collection_deleted (GkdSecretService *self,
+ const gchar *collection_path)
+{
+ DBusMessage *message;
+
+ g_return_if_fail (GKD_SECRET_IS_SERVICE (self));
+ g_return_if_fail (collection_path != NULL);
+
+ message = dbus_message_new_signal (SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "CollectionDeleted");
+ dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &collection_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (self->connection, message, NULL))
+ g_return_if_reached ();
+ dbus_message_unref (message);
+
+ emit_collections_properties_changed (self);
+}
diff --git a/daemon/dbus/gkd-secret-service.h b/daemon/dbus/gkd-secret-service.h
index 9fc303d..981854b 100644
--- a/daemon/dbus/gkd-secret-service.h
+++ b/daemon/dbus/gkd-secret-service.h
@@ -79,4 +79,10 @@ void gkd_secret_service_publish_dispatch (GkdSecretSer
const gchar *caller,
GkdSecretDispatch *object);
+void gkd_secret_service_emit_collection_created (GkdSecretService *self,
+ const gchar *collection_path);
+
+void gkd_secret_service_emit_collection_deleted (GkdSecretService *self,
+ const gchar *collection_path);
+
#endif /* ___SECRET_SERVICE_H__ */
diff --git a/daemon/dbus/gkd-secret-unlock.c b/daemon/dbus/gkd-secret-unlock.c
index 2e3fbed..82330c4 100644
--- a/daemon/dbus/gkd-secret-unlock.c
+++ b/daemon/dbus/gkd-secret-unlock.c
@@ -96,6 +96,21 @@ lookup_collection (GkdSecretUnlock *self, const gchar *path)
return gkd_secret_objects_lookup_collection (objects, self->caller, path);
}
+static void
+emit_collection_unlocked (GkdSecretUnlock *self,
+ const gchar *path)
+{
+ GkdSecretObjects *objects;
+ GckObject *collection;
+
+ objects = gkd_secret_service_get_objects (self->service);
+ collection = gkd_secret_objects_lookup_collection (objects, self->caller, path);
+ if (collection != NULL) {
+ gkd_secret_objects_emit_collection_locked (objects, collection);
+ g_object_unref (collection);
+ }
+}
+
static gboolean
check_locked_collection (GckObject *collection, gboolean *locked)
{
@@ -195,6 +210,7 @@ on_unlock_complete (GObject *object, GAsyncResult *res, gpointer user_data)
/* Successfully authentication */
if (cred) {
g_object_unref (cred);
+ emit_collection_unlocked (self, self->current);
g_array_append_val (self->results, self->current);
self->current = NULL;
perform_next_unlock (self);
diff --git a/daemon/dbus/tests/Makefile.am b/daemon/dbus/tests/Makefile.am
index ad89268..6c1daca 100644
--- a/daemon/dbus/tests/Makefile.am
+++ b/daemon/dbus/tests/Makefile.am
@@ -2,14 +2,23 @@
INCLUDES = \
-I$(top_srcdir)/daemon/dbus \
-DSRCDIR="\"@abs_srcdir \"" \
+ -DTOP_SRCDIR="\"@abs_top_srcdir \"" \
+ -DGCR_API_SUBJECT_TO_CHANGE \
$(DAEMON_CFLAGS) \
+ $(GCR_BASE_CFLAGS) \
+ $(GIO_CFLAGS) \
$(GLIB_CFLAGS)
LDADD = \
- $(top_builddir)/daemon/dbus/libgkd-dbus.la
+ $(top_builddir)/daemon/dbus/libgkd-dbus.la \
+ $(top_builddir)/egg/libegg-test.la \
+ $(GCR_BASE_LIBS) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS)
TEST_PROGS = \
- test-secret-util
+ test-secret-util \
+ test-secret-signals
check_PROGRAMS = $(TEST_PROGS)
diff --git a/daemon/dbus/tests/files/test.keyring b/daemon/dbus/tests/files/test.keyring
new file mode 100644
index 0000000..f53ed5d
Binary files /dev/null and b/daemon/dbus/tests/files/test.keyring differ
diff --git a/daemon/dbus/tests/test-secret-signals.c b/daemon/dbus/tests/test-secret-signals.c
new file mode 100644
index 0000000..0a99ecb
--- /dev/null
+++ b/daemon/dbus/tests/test-secret-signals.c
@@ -0,0 +1,916 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-secret-util.c: Test secret utils
+
+ Copyright (C) 2012 Red Hat Inc
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stefw gnome org>
+*/
+
+#include "config.h"
+
+#include "gkd-secret-types.h"
+
+#include "egg/egg-testing.h"
+
+#include <gcr/gcr-base.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <fcntl.h>
+
+typedef struct {
+ gchar *path;
+ gchar *iface;
+ gchar *name;
+ GVariant *parameters;
+} ReceivedSignal;
+
+typedef struct {
+ GDBusConnection *connection;
+ gchar *service_name;
+ const gchar *mock_prompter;
+ GPid service_pid;
+ gboolean service_available;
+ gchar *service_session;
+ guint watch_id;
+ guint signal_id;
+ gchar *directory;
+ GList *received_signals;
+} Test;
+
+static void
+on_test_service_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ Test *test = user_data;
+ if (!test->connection)
+ test->connection = g_object_ref (connection);
+ test->service_available = TRUE;
+ egg_test_wait_stop ();
+}
+
+static void
+on_test_service_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ Test *test = user_data;
+ if (test->service_available) {
+ test->service_available = FALSE;
+ egg_test_wait_stop ();
+ }
+}
+
+static void
+on_service_spawned (gpointer user_data)
+{
+ Test *test = user_data;
+ int fd;
+
+ g_setenv ("GNOME_KEYRING_TEST_PATH", test->directory, TRUE);
+ g_setenv ("GNOME_KEYRING_TEST_SERVICE", test->service_name, TRUE);
+ g_setenv ("GNOME_KEYRING_TEST_PROMPTER", test->mock_prompter, TRUE);
+
+ fd = g_open ("/dev/null", O_WRONLY, 0);
+ if (fd != -1)
+ dup2 (fd, 1);
+}
+
+static GVariant *
+build_secret_value (Test *test,
+ const gchar *value)
+{
+ return g_variant_new ("(o ay@ays)", test->service_session,
+ g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, "", 0, 1),
+ g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, value, strlen (value), 1),
+ "text/plain");
+}
+
+static void
+on_signal_received (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ Test *test = user_data;
+ ReceivedSignal *sig;
+
+ g_assert (object_path != NULL);
+ g_assert (interface_name != NULL);
+ g_assert (signal_name != NULL);
+ g_assert (parameters != NULL);
+
+ sig = g_slice_new0 (ReceivedSignal);
+ sig->path = g_strdup (object_path);
+ sig->iface = g_strdup (interface_name);
+ sig->name = g_strdup (signal_name);
+ sig->parameters = g_variant_ref (parameters);
+ test->received_signals = g_list_prepend (test->received_signals, sig);
+}
+
+static void
+received_signal_free (gpointer data)
+{
+ ReceivedSignal *sig = data;
+ g_free (sig->path);
+ g_free (sig->iface);
+ g_free (sig->name);
+ g_variant_unref (sig->parameters);
+ g_slice_free (ReceivedSignal, sig);
+}
+
+static void
+received_signals_flush (Test *test)
+{
+ g_list_free_full (test->received_signals, received_signal_free);
+ test->received_signals = NULL;
+}
+
+static void
+expect_signal_with_path (Test *test,
+ const gchar *signal_path,
+ const gchar *signal_iface,
+ const gchar *signal_name,
+ const gchar *param_path)
+{
+ ReceivedSignal *sig;
+ const gchar *path;
+ GList *l;
+
+ g_assert (signal_path != NULL);
+ g_assert (signal_iface != NULL);
+ g_assert (signal_name != NULL);
+ g_assert (param_path != NULL);
+
+ for (l = test->received_signals; l != NULL; l = g_list_next (l)) {
+ sig = l->data;
+
+ if (g_str_equal (signal_path, sig->path) &&
+ g_str_equal (signal_iface, sig->iface) &&
+ g_str_equal (signal_name, sig->name)) {
+ g_assert (g_variant_is_of_type (sig->parameters, G_VARIANT_TYPE ("(o)")));
+ g_variant_get (sig->parameters, "(&o)", &path);
+ if (!g_str_equal (path, param_path)) {
+ g_critical ("received invalid path from signal %s on interface %s at object %s: "
+ "expected path %s but got %s",
+ sig->name, sig->iface, sig->path, param_path, path);
+ }
+
+ return;
+ }
+ }
+
+ g_critical ("didn't receive signal %s on interface %s at object %s",
+ signal_name, signal_iface, signal_path);
+}
+
+static void
+expect_property_changed (Test *test,
+ const gchar *signal_path,
+ const gchar *property_iface,
+ const gchar *property_name)
+{
+ ReceivedSignal *sig;
+ const gchar *iface;
+ GVariant *properties;
+ GVariant *invalidated;
+ GVariant *value;
+ GList *l;
+
+ g_assert (signal_path != NULL);
+ g_assert (property_iface != NULL);
+ g_assert (property_name != NULL);
+
+ for (l = test->received_signals; l != NULL; l = g_list_next (l)) {
+ sig = l->data;
+
+ if (g_str_equal (signal_path, sig->path) &&
+ g_str_equal ("org.freedesktop.DBus.Properties", sig->iface) &&
+ g_str_equal ("PropertiesChanged", sig->name)) {
+ value = NULL;
+ g_assert (g_variant_is_of_type (sig->parameters, G_VARIANT_TYPE ("(sa{sv}as)")));
+
+ g_variant_get (sig->parameters, "(&s a{sv}@as)", &iface, &properties, &invalidated);
+ if (g_str_equal (iface, property_iface)) {
+ value = g_variant_lookup_value (properties, property_name, NULL);
+ g_variant_unref (value);
+ }
+
+ g_variant_unref (properties);
+ g_variant_unref (invalidated);
+
+ if (value != NULL)
+ return;
+ }
+ }
+
+ g_critical ("didn't receive PropertiesChanged for %s property on interface %s at object %s",
+ property_name, property_iface, signal_path);
+}
+
+static void
+on_complete_get_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **res = user_data;
+ g_assert (res != NULL);
+ g_assert (*res == NULL);
+ *res = g_object_ref (result);
+ egg_test_wait_stop ();
+}
+
+static GVariant *
+dbus_call_perform (Test *test,
+ const gchar *object_path,
+ const gchar *interface,
+ const gchar *member,
+ GVariant *parameters,
+ const GVariantType *restype,
+ GError **error)
+{
+ GAsyncResult *result = NULL;
+ GVariant *retval;
+
+ /*
+ * Do an async call with a full main loop, so that the signals
+ * arrive before the method result.
+ */
+
+ g_dbus_connection_call (test->connection,
+ test->service_name,
+ object_path,
+ interface,
+ member,
+ parameters,
+ restype,
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL,
+ on_complete_get_result,
+ &result);
+
+ g_assert (result == NULL);
+ egg_test_wait ();
+ g_assert (result != NULL);
+
+ retval = g_dbus_connection_call_finish (test->connection,
+ result, error);
+ g_object_unref (result);
+
+ return retval;
+}
+
+static void
+setup (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GVariant *retval;
+ GVariant *output;
+
+ gchar *args[] = {
+ TOP_SRCDIR "/daemon/gnome-keyring-daemon",
+ "--foreground",
+ "--control-directory",
+ "/tmp/keyring-test",
+ "--components",
+ "secrets",
+ NULL,
+ };
+
+ test->service_name = g_strdup_printf ("org.gnome.keyring.Test.t%d", getpid ());
+
+ test->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, test->service_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ on_test_service_appeared,
+ on_test_service_vanished,
+ test, NULL);
+
+ test->mock_prompter = gcr_mock_prompter_start ();
+ g_assert (test->mock_prompter != NULL);
+
+ test->directory = egg_tests_create_scratch_directory (
+ SRCDIR "/files/test.keyring",
+ NULL);
+
+ if (!g_spawn_async (NULL, args, NULL,
+ G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_DO_NOT_REAP_CHILD,
+ on_service_spawned, test, &test->service_pid, &error)) {
+ g_error ("couldn't start gnome-keyring-daemon for testing: %s", error->message);
+ g_assert_not_reached ();
+ }
+
+ if (!test->service_available) {
+ egg_test_wait ();
+
+ if (!test->service_available) {
+ g_warning ("Couldn't start gnome-keyring-daemon test service. ");
+ g_assert_not_reached ();
+ }
+ }
+
+ /* Set by on_test_service_appeared */
+ g_assert (test->connection != NULL);
+
+ /* Establish a plain session with the daemon */
+ retval = g_dbus_connection_call_sync (test->connection,
+ test->service_name,
+ SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "OpenSession",
+ g_variant_new ("(s v)", "plain",
+ g_variant_new_variant (g_variant_new_string (""))),
+ G_VARIANT_TYPE ("(vo)"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, &error);
+ g_assert_no_error (error);
+
+ g_variant_get (retval, "(@vo)", &output, &test->service_session);
+ g_variant_unref (output);
+ g_variant_unref (retval);
+
+ /* Unlock the test collection */
+ retval = g_dbus_connection_call_sync (test->connection,
+ test->service_name,
+ SECRET_SERVICE_PATH,
+ INTERNAL_SERVICE_INTERFACE,
+ "UnlockWithMasterPassword",
+ g_variant_new ("(o@(oayays))",
+ "/org/freedesktop/secrets/collection/test",
+ build_secret_value (test, "booo")),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NO_AUTO_START,
+ -1, NULL, &error);
+ g_assert_no_error (error);
+ g_variant_unref (retval);
+
+ /* Wait for the prompt's completed signal */
+ test->signal_id = g_dbus_connection_signal_subscribe (test->connection,
+ test->service_name,
+ NULL, NULL, NULL, NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_signal_received,
+ test, NULL);
+
+ received_signals_flush (test);
+
+}
+
+static void
+setup_locked (Test *test,
+ gconstpointer unused)
+{
+ GVariant *element;
+ GVariant *retval;
+ GError *error = NULL;
+ const gchar *prompt;
+ GVariant *locked;
+
+ /* Main setup */
+ setup (test, unused);
+
+ element = g_variant_new_object_path ("/org/freedesktop/secrets/collection/test");
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "Lock",
+ g_variant_new ("(@ao)",
+ g_variant_new_array (G_VARIANT_TYPE ("o"), &element, 1)),
+ G_VARIANT_TYPE ("(aoo)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Not expecting a prompt */
+ g_variant_get (retval, "(@ao&o)", &locked, &prompt);
+ g_assert_cmpstr (prompt, ==, "/");
+ g_variant_unref (locked);
+ g_variant_unref (retval);
+
+ /* Don't carry over any received signals into test */
+ received_signals_flush (test);
+}
+
+static void
+teardown (Test *test,
+ gconstpointer unused)
+{
+ received_signals_flush (test);
+
+ g_dbus_connection_signal_unsubscribe (test->connection, test->signal_id);
+
+ if (test->service_pid)
+ kill (test->service_pid, SIGTERM);
+
+ if (test->service_available) {
+ egg_test_wait ();
+ if (test->service_available) {
+ g_warning ("Couldn't stop gnome-keyring-daemon test service.");
+ g_assert_not_reached ();
+ }
+ }
+
+ if (test->watch_id)
+ g_bus_unwatch_name (test->watch_id);
+
+ g_free (test->service_name);
+ g_free (test->service_session);
+
+ if (test->connection)
+ g_object_unref (test->connection);
+
+ gcr_mock_prompter_stop ();
+
+ egg_tests_remove_scratch_directory (test->directory);
+ g_free (test->directory);
+}
+
+
+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)
+{
+ GVariant **prompt_result = user_data;
+ gboolean dismissed;
+ GVariant *result;
+
+ g_assert (prompt_result != NULL);
+ g_assert (*prompt_result == NULL);
+
+ g_assert (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(bv)")));
+ g_variant_get (parameters, "(b v)", &dismissed, &result);
+
+ if (dismissed)
+ *prompt_result = NULL;
+ else
+ *prompt_result = g_variant_ref (result);
+ g_variant_unref (result);
+
+ egg_test_wait_stop ();
+}
+
+static GVariant *
+prompt_password_perform (Test *test,
+ const gchar *prompt_path,
+ const gchar *password,
+ const GVariantType *type)
+{
+ GVariant *prompt_result = NULL;
+ GError *error = NULL;
+ GVariant *inside;
+ GVariant *retval;
+ guint sig;
+
+ /* Tell the mock prompter which password to use */
+ gcr_mock_prompter_expect_password_ok (password, NULL);
+
+ /* Wait for the prompt's completed signal */
+ sig = g_dbus_connection_signal_subscribe (test->connection,
+ test->service_name,
+ SECRET_PROMPT_INTERFACE,
+ "Completed",
+ prompt_path,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_prompt_completed,
+ &prompt_result,
+ NULL);
+
+ /* Perform the prompt, this will use the mock prompter */
+ retval = g_dbus_connection_call_sync (test->connection,
+ test->service_name,
+ prompt_path,
+ SECRET_PROMPT_INTERFACE,
+ "Prompt",
+ g_variant_new ("(s)", ""),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ g_assert_no_error (error);
+ g_variant_unref (retval);
+
+ egg_test_wait ();
+
+ /* Done, now stop waiting for the prompts signal, make sure mock was used */
+ g_dbus_connection_signal_unsubscribe (test->connection, sig);
+ g_assert (!gcr_mock_prompter_is_expecting ());
+
+ /* Check prompt result for right type */
+ g_assert (prompt_result != NULL);
+ inside = g_variant_get_variant (prompt_result);
+ g_assert (g_variant_is_of_type (inside, type));
+ g_variant_unref (prompt_result);
+
+ return inside;
+}
+
+static void
+test_collection_created (Test *test,
+ gconstpointer unused)
+{
+ const gchar *collection;
+ GError *error = NULL;
+ const gchar *prompt;
+ GVariant *properties;
+ GVariant *retval;
+ GVariant *result;
+ GVariant *label;
+
+ /* Create a new collection */
+ label = g_variant_new_dict_entry (g_variant_new_string ("org.freedesktop.Secret.Collection.Label"),
+ g_variant_new_variant (g_variant_new_string ("My Collection")));
+ properties = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), &label, 1);
+
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "CreateCollection",
+ g_variant_new ("(@a{sv}s)", properties, ""),
+ G_VARIANT_TYPE ("(oo)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* We expect that a prompt is necessary */
+ g_variant_get (retval, "(&o&o)", &collection, &prompt);
+ g_assert_cmpstr (collection, ==, "/");
+ g_assert_cmpstr (prompt, !=, "/");
+
+ /*
+ * Perform the password prompt to create the collection, which returns
+ * the new collection path
+ */
+ result = prompt_password_perform (test, prompt, "booo", G_VARIANT_TYPE_OBJECT_PATH);
+ g_variant_unref (retval);
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH, SECRET_SERVICE_INTERFACE,
+ "CollectionCreated", g_variant_get_string (result, NULL));
+ expect_property_changed (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "Collections");
+
+ g_variant_unref (result);
+}
+
+static void
+test_collection_created_no_prompt (Test *test,
+ gconstpointer unused)
+{
+ const gchar *collection;
+ GError *error = NULL;
+ GVariant *properties;
+ GVariant *retval;
+ GVariant *label;
+
+ /* Create a new collection */
+ label = g_variant_new_dict_entry (g_variant_new_string ("org.freedesktop.Secret.Collection.Label"),
+ g_variant_new_variant (g_variant_new_string ("Without Prompt")));
+ properties = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), &label, 1);
+
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ INTERNAL_SERVICE_INTERFACE,
+ "CreateWithMasterPassword",
+ g_variant_new ("(@a{sv}@(oayays))",
+ properties,
+ build_secret_value (test, "booo")),
+ G_VARIANT_TYPE ("(o)"),
+ &error);
+ g_assert_no_error (error);
+
+ g_variant_get (retval, "(&o)", &collection);
+ g_assert_cmpstr (collection, !=, "/");
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH, SECRET_SERVICE_INTERFACE,
+ "CollectionCreated", collection);
+ expect_property_changed (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "Collections");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_collection_deleted (Test *test,
+ gconstpointer unused)
+{
+ const gchar *prompt;
+ GError *error = NULL;
+ GVariant *retval;
+
+ /* Delete a collection */
+ retval = dbus_call_perform (test,
+ "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE,
+ "Delete",
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("(o)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Expect that no prompt is returned */
+ g_variant_get (retval, "(&o)", &prompt);
+ g_assert_cmpstr (prompt, ==, "/");
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH, SECRET_SERVICE_INTERFACE,
+ "CollectionDeleted", "/org/freedesktop/secrets/collection/test");
+ expect_property_changed (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "Collections");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_collection_changed (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = dbus_call_perform (test,
+ "/org/freedesktop/secrets/collection/test",
+ "org.freedesktop.DBus.Properties",
+ "Set",
+ g_variant_new ("(ssv)",
+ SECRET_COLLECTION_INTERFACE,
+ "Label",
+ g_variant_new_string ("New label")),
+ G_VARIANT_TYPE ("()"),
+ &error);
+ g_assert_no_error (error);
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "CollectionChanged",
+ "/org/freedesktop/secrets/collection/test");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Label");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_collection_lock (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ const gchar *prompt;
+ GVariant *element;
+ GVariant *locked;
+ GVariant *retval;
+
+ element = g_variant_new_object_path ("/org/freedesktop/secrets/collection/test");
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "Lock",
+ g_variant_new ("(@ao)",
+ g_variant_new_array (G_VARIANT_TYPE ("o"), &element, 1)),
+ G_VARIANT_TYPE ("(aoo)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Not expecting a prompt */
+ g_variant_get (retval, "(@ao&o)", &locked, &prompt);
+ g_assert_cmpstr (prompt, ==, "/");
+ g_variant_unref (locked);
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "CollectionChanged",
+ "/org/freedesktop/secrets/collection/test");
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemChanged",
+ "/org/freedesktop/secrets/collection/test/1");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Locked");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test/1",
+ SECRET_ITEM_INTERFACE, "Locked");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_collection_unlock (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ const gchar *prompt;
+ GVariant *unlocked;
+ GVariant *retval;
+ GVariant *element;
+
+ element = g_variant_new_object_path ("/org/freedesktop/secrets/collection/test");
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE,
+ "Unlock",
+ g_variant_new ("(@ao)",
+ g_variant_new_array (G_VARIANT_TYPE ("o"), &element, 1)),
+ G_VARIANT_TYPE ("(aoo)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Not expecting a prompt */
+ g_variant_get (retval, "(@ao&o)", &unlocked, &prompt);
+ g_assert_cmpstr (prompt, !=, "/");
+ g_variant_unref (unlocked);
+
+ unlocked = prompt_password_perform (test, prompt, "booo", G_VARIANT_TYPE ("ao"));
+ g_variant_unref (unlocked);
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "CollectionChanged",
+ "/org/freedesktop/secrets/collection/test");
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemChanged",
+ "/org/freedesktop/secrets/collection/test/1");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Locked");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test/1",
+ SECRET_ITEM_INTERFACE, "Locked");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_collection_unlock_no_prompt (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = dbus_call_perform (test,
+ SECRET_SERVICE_PATH,
+ INTERNAL_SERVICE_INTERFACE,
+ "UnlockWithMasterPassword",
+ g_variant_new ("(o@(oayays))",
+ "/org/freedesktop/secrets/collection/test",
+ build_secret_value (test, "booo")),
+ G_VARIANT_TYPE ("()"),
+ &error);
+ g_assert_no_error (error);
+
+ expect_signal_with_path (test, SECRET_SERVICE_PATH,
+ SECRET_SERVICE_INTERFACE, "CollectionChanged",
+ "/org/freedesktop/secrets/collection/test");
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemChanged",
+ "/org/freedesktop/secrets/collection/test/1");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Locked");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test/1",
+ SECRET_ITEM_INTERFACE, "Locked");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_item_created (Test *test,
+ gconstpointer unused)
+{
+ const gchar *item;
+ const gchar *prompt;
+ GError *error = NULL;
+ GVariant *properties;
+ GVariant *retval;
+ GVariant *label;
+
+ /* Create a new collection */
+ label = g_variant_new_dict_entry (g_variant_new_string ("org.freedesktop.Secret.Item.Label"),
+ g_variant_new_variant (g_variant_new_string ("My Item")));
+ properties = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), &label, 1);
+
+ retval = dbus_call_perform (test,
+ "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE,
+ "CreateItem",
+ g_variant_new ("(@a{sv}@(oayays)b)",
+ properties,
+ build_secret_value (test, "booo"),
+ FALSE),
+ G_VARIANT_TYPE ("(oo)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Not expecting a prompt */
+ g_variant_get (retval, "(&o&o)", &item, &prompt);
+ g_assert_cmpstr (item, !=, "/");
+ g_assert_cmpstr (prompt, ==, "/");
+
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemCreated", item);
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Items");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_item_deleted (Test *test,
+ gconstpointer unused)
+{
+ const gchar *prompt;
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = dbus_call_perform (test,
+ "/org/freedesktop/secrets/collection/test/1",
+ SECRET_ITEM_INTERFACE,
+ "Delete",
+ g_variant_new ("()"),
+ G_VARIANT_TYPE ("(o)"),
+ &error);
+ g_assert_no_error (error);
+
+ /* Not expecting a prompt */
+ g_variant_get (retval, "(&o)", &prompt);
+ g_assert_cmpstr (prompt, ==, "/");
+
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemDeleted",
+ "/org/freedesktop/secrets/collection/test/1");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "Items");
+
+ g_variant_unref (retval);
+}
+
+static void
+test_item_changed (Test *test,
+ gconstpointer unused)
+{
+ GError *error = NULL;
+ GVariant *retval;
+
+ retval = dbus_call_perform (test,
+ "/org/freedesktop/secrets/collection/test/1",
+ "org.freedesktop.DBus.Properties",
+ "Set",
+ g_variant_new ("(ssv)",
+ SECRET_ITEM_INTERFACE,
+ "Label",
+ g_variant_new_string ("New label")),
+ G_VARIANT_TYPE ("()"),
+ &error);
+ g_assert_no_error (error);
+
+ expect_signal_with_path (test, "/org/freedesktop/secrets/collection/test",
+ SECRET_COLLECTION_INTERFACE, "ItemChanged",
+ "/org/freedesktop/secrets/collection/test/1");
+ expect_property_changed (test, "/org/freedesktop/secrets/collection/test/1",
+ SECRET_ITEM_INTERFACE, "Label");
+
+ g_variant_unref (retval);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/secret-signals/collection-created", Test, NULL,
+ setup, test_collection_created, teardown);
+ g_test_add ("/secret-signals/collection-created-no-prompt", Test, NULL,
+ setup, test_collection_created_no_prompt, teardown);
+ g_test_add ("/secret-signals/collection-changed", Test, NULL,
+ setup, test_collection_changed, teardown);
+ g_test_add ("/secret-signals/collection-deleted", Test, NULL,
+ setup, test_collection_deleted, teardown);
+ g_test_add ("/secret-signals/collection-lock", Test, NULL,
+ setup, test_collection_lock, teardown);
+ g_test_add ("/secret-signals/collection-unlock", Test, NULL,
+ setup_locked, test_collection_unlock, teardown);
+ g_test_add ("/secret-signals/collection-unlock-no-prompt", Test, NULL,
+ setup_locked, test_collection_unlock_no_prompt, teardown);
+ g_test_add ("/secret-signals/item-created", Test, NULL,
+ setup, test_item_created, teardown);
+ g_test_add ("/secret-signals/item-changed", Test, NULL,
+ setup, test_item_changed, teardown);
+ g_test_add ("/secret-signals/item-deleted", Test, NULL,
+ setup, test_item_deleted, teardown);
+
+ return egg_tests_run_with_loop ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]