From 889f6d66b72904df779ff52054ee86abc03bcd7e Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 5 Jul 2012 19:08:09 +0200 Subject: [PATCH] Make secret_service_search() able to unlock, load secrets * Turn secret_service_search() and friends into a more convenient API, so that callers can get attributes, unlocking, and secrets if so desired. * Also support retrieving either one secret, or all of them. --- .../libsecret/libsecret-sections.txt | 3 + library/secret-methods.c | 285 ++++++++++----- library/secret-service.h | 19 +- library/tests/test-methods.c | 324 ++++++++++++------ 4 files changed, 441 insertions(+), 190 deletions(-) diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index cd014ef..805ee22 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -186,6 +186,7 @@ secret_service_ensure_session_sync secret_service_ensure_collections secret_service_ensure_collections_finish secret_service_ensure_collections_sync +SecretSearchFlags secret_service_search secret_service_search_finish secret_service_search_sync @@ -219,9 +220,11 @@ SECRET_IS_SERVICE_CLASS SECRET_SERVICE SECRET_SERVICE_CLASS SECRET_SERVICE_GET_CLASS +SECRET_TYPE_SEARCH_FLAGS SECRET_TYPE_SERVICE SECRET_TYPE_SERVICE_FLAGS SecretServicePrivate +secret_search_flags_get_type secret_service_flags_get_type secret_service_get_type diff --git a/library/secret-methods.c b/library/secret-methods.c index 151e5f7..df43525 100644 --- a/library/secret-methods.c +++ b/library/secret-methods.c @@ -25,17 +25,20 @@ #include "secret-value.h" typedef struct { + SecretService *service; GCancellable *cancellable; GHashTable *items; gchar **unlocked; gchar **locked; guint loading; + SecretSearchFlags flags; } SearchClosure; static void search_closure_free (gpointer data) { SearchClosure *closure = data; + g_object_unref (closure->service); g_clear_object (&closure->cancellable); g_hash_table_unref (closure->items); g_strfreev (closure->unlocked); @@ -51,6 +54,64 @@ search_closure_take_item (SearchClosure *closure, g_hash_table_insert (closure->items, (gpointer)path, item); } +static GList * +search_closure_build_items (SearchClosure *closure, + gchar **paths) +{ + GList *results = NULL; + SecretItem *item; + guint i; + + for (i = 0; paths[i]; i++) { + item = g_hash_table_lookup (closure->items, paths[i]); + if (item != NULL) + results = g_list_prepend (results, g_object_ref (item)); + } + + return g_list_reverse (results); +} + +static void +on_search_secrets (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + + /* Note that we ignore any unlock failure */ + secret_item_load_secrets_finish (result, NULL); + + g_simple_async_result_complete (async); + g_object_unref (async); +} + +static void +on_search_unlocked (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async); + GList *items; + + /* Note that we ignore any unlock failure */ + secret_service_unlock_finish (search->service, result, NULL, NULL); + + /* If loading secrets ... locked items automatically ignored */ + if (search->flags & SECRET_SEARCH_LOAD_SECRETS) { + items = g_hash_table_get_values (search->items); + secret_item_load_secrets (items, search->cancellable, + on_search_secrets, g_object_ref (async)); + g_list_free (items); + + /* No additional options, just complete */ + } else { + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + static void on_search_loaded (GObject *source, GAsyncResult *result, @@ -60,6 +121,7 @@ on_search_loaded (GObject *source, SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; SecretItem *item; + GList *items; closure->loading--; @@ -69,8 +131,29 @@ on_search_loaded (GObject *source, if (item != NULL) search_closure_take_item (closure, item); - if (closure->loading == 0) - g_simple_async_result_complete (res); + + /* We're done loading, lets go to the next step */ + if (closure->loading == 0) { + + /* If unlocking then unlock all the locked items */ + if (closure->flags & SECRET_SEARCH_UNLOCK) { + items = search_closure_build_items (closure, closure->locked); + secret_service_unlock (closure->service, items, closure->cancellable, + on_search_unlocked, g_object_ref (res)); + g_list_free_full (items, g_object_unref); + + /* If loading secrets ... locked items automatically ignored */ + } else if (closure->flags & SECRET_SEARCH_LOAD_SECRETS) { + items = g_hash_table_get_values (closure->items); + secret_item_load_secrets (items, closure->cancellable, + on_search_secrets, g_object_ref (res)); + g_list_free (items); + + /* No additional options, just complete */ + } else { + g_simple_async_result_complete (res); + } + } g_object_unref (res); } @@ -100,24 +183,32 @@ on_search_paths (GObject *source, { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - SecretService *self = SECRET_SERVICE (source); + SecretService *self = closure->service; GError *error = NULL; + gint want = 1; guint i; - if (!secret_service_search_for_paths_finish (self, result, &closure->unlocked, - &closure->locked, &error)) { + secret_service_search_for_paths_finish (self, result, &closure->unlocked, + &closure->locked, &error); + if (error == NULL) { + want = 1; + if (closure->flags & SECRET_SEARCH_ALL) + want = G_MAXINT; + + for (i = 0; closure->loading < want && closure->unlocked[i] != NULL; i++) + search_load_item_async (self, res, closure, closure->unlocked[i]); + for (i = 0; closure->loading < want && closure->locked[i] != NULL; i++) + search_load_item_async (self, res, closure, closure->locked[i]); + + /* No items loading, complete operation now */ + if (closure->loading == 0) + g_simple_async_result_complete (res); + + } else { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); } - for (i = 0; closure->unlocked[i] != NULL; i++) - search_load_item_async (self, res, closure, closure->unlocked[i]); - for (i = 0; closure->locked[i] != NULL; i++) - search_load_item_async (self, res, closure, closure->locked[i]); - - if (closure->loading == 0) - g_simple_async_result_complete (res); - g_object_unref (res); } @@ -125,6 +216,7 @@ on_search_paths (GObject *source, * secret_service_search: * @self: the secret service * @attributes: (element-type utf8 utf8): search for items matching these attributes + * @flags: search option flags * @cancellable: optional cancellation object * @callback: called when the operation completes * @user_data: data to pass to the callback @@ -132,16 +224,23 @@ on_search_paths (GObject *source, * Search for items matching the @attributes. All collections are searched. * The @attributes should be a table of string keys and string values. * - * This function returns immediately and completes asynchronously. + * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the + * search will be returned. Otherwise only the first item will be returned. + * This is almost always the unlocked item that was most recently stored. * - * When your callback is called use secret_service_search_finish() - * to get the results of this function. #SecretItem proxy objects will be - * returned. If you prefer to only have the items D-Bus object paths returned, - * then then use the secret_service_search_for_paths() function. + * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked + * if necessary. In either case, locked and unlocked items will match the + * search and be returned. If the unlock fails, the search does not fail. + * + * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items will have + * their secret values loaded and available via secret_item_get_secret(). + * + * This function returns immediately and completes asynchronously. */ void secret_service_search (SecretService *self, GHashTable *attributes, + SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -156,8 +255,10 @@ secret_service_search (SecretService *self, res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, secret_service_search); closure = g_slice_new0 (SearchClosure); + closure->service = g_object_ref (self); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + closure->flags = flags; g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free); secret_service_search_for_paths (self, attributes, cancellable, @@ -166,53 +267,25 @@ secret_service_search (SecretService *self, g_object_unref (res); } -static GList * -search_finish_build (gchar **paths, - SearchClosure *closure) -{ - GList *results = NULL; - SecretItem *item; - guint i; - - for (i = 0; paths[i]; i++) { - item = g_hash_table_lookup (closure->items, paths[i]); - if (item != NULL) - results = g_list_prepend (results, g_object_ref (item)); - } - - return g_list_reverse (results); -} - /** * secret_service_search_finish: * @self: the secret service * @result: asynchronous result passed to callback - * @unlocked: (out) (transfer full) (element-type Secret.Item) (allow-none): - * location to place a list of matching items which were not locked. - * @locked: (out) (transfer full) (element-type Secret.Item) (allow-none): - * location to place a list of matching items which were locked. * @error: location to place error on failure * * Complete asynchronous operation to search for items. * - * Matching items that are locked or unlocked are placed in the @locked or - * @unlocked lists respectively. - * - * #SecretItem proxy objects will be returned. If you prefer to only have - * the items' D-Bus object paths returned, then then use the - * secret_service_search_for_paths() function. - * - * Returns: whether the search was successful or not + * Returns: (transfer full) (element-type Secret.Item): + * a list of items that matched the search */ -gboolean +GList * secret_service_search_finish (SecretService *self, GAsyncResult *result, - GList **unlocked, - GList **locked, GError **error) { GSimpleAsyncResult *res; SearchClosure *closure; + GList *items; g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -225,12 +298,11 @@ secret_service_search_finish (SecretService *self, return FALSE; closure = g_simple_async_result_get_op_res_gpointer (res); - if (unlocked) - *unlocked = search_finish_build (closure->unlocked, closure); - if (locked) - *locked = search_finish_build (closure->locked, closure); - - return TRUE; + if (closure->unlocked) + items = search_closure_build_items (closure, closure->unlocked); + if (closure->locked) + items = g_list_concat (items, search_closure_build_items (closure, closure->locked)); + return items; } static gboolean @@ -238,26 +310,27 @@ service_load_items_sync (SecretService *self, GCancellable *cancellable, gchar **paths, GList **items, + gint want, + gint *have, GError **error) { SecretItem *item; - GList *result = NULL; guint i; - for (i = 0; paths[i] != NULL; i++) { + for (i = 0; *have < want && paths[i] != NULL; i++) { item = _secret_service_find_item_instance (self, paths[i]); if (item == NULL) item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE, cancellable, error); if (item == NULL) { - g_list_free_full (result, g_object_unref); return FALSE; + } else { - result = g_list_prepend (result, item); + *items = g_list_prepend (*items, item); + (*have)++; } } - *items = g_list_reverse (result); return TRUE; } @@ -265,60 +338,98 @@ service_load_items_sync (SecretService *self, * secret_service_search_sync: * @self: the secret service * @attributes: (element-type utf8 utf8): search for items matching these attributes + * @flags: search option flags * @cancellable: optional cancellation object - * @unlocked: (out) (transfer full) (element-type Secret.Item) (allow-none): - * location to place a list of matching items which were not locked. - * @locked: (out) (transfer full) (element-type Secret.Item) (allow-none): - * location to place a list of matching items which were locked. * @error: location to place error on failure * * Search for items matching the @attributes. All collections are searched. * The @attributes should be a table of string keys and string values. * + * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the + * search will be returned. Otherwise only the first item will be returned. + * This is almost always the unlocked item that was most recently stored. + * + * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked + * if necessary. In either case, locked and unlocked items will match the + * search and be returned. If the unlock fails, the search does not fail. + * + * If %SECRET_SEARCH_LOAD_SECRETS is set in @flags, then the items' secret + * values will be loaded for any unlocked items. Loaded item secret values + * are available via secret_item_get_secret(). If the load of a secret values + * fail, then the + * * This function may block indefinetely. Use the asynchronous version * in user interface threads. * - * Matching items that are locked or unlocked are placed - * in the @locked or @unlocked lists respectively. - * - * #SecretItem proxy objects will be returned. If you prefer to only have - * the items' D-Bus object paths returned, then then use the - * secret_service_search_sync() function. - * - * Returns: whether the search was successful or not + * Returns: (transfer full) (element-type Secret.Item): + * a list of items that matched the search */ -gboolean +GList * secret_service_search_sync (SecretService *self, GHashTable *attributes, + SecretSearchFlags flags, GCancellable *cancellable, - GList **unlocked, - GList **locked, GError **error) { gchar **unlocked_paths = NULL; gchar **locked_paths = NULL; + GList *items = NULL; + GList *locked = NULL; + GList *unlocked = NULL; gboolean ret; + gint want; + gint have; - g_return_val_if_fail (SECRET_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); + g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (!secret_service_search_for_paths_sync (self, attributes, cancellable, - unlocked ? &unlocked_paths : NULL, - locked ? &locked_paths : NULL, error)) - return FALSE; + &unlocked_paths, &locked_paths, error)) + return NULL; ret = TRUE; - if (unlocked) - ret = service_load_items_sync (self, cancellable, unlocked_paths, unlocked, error); - if (ret && locked) - ret = service_load_items_sync (self, cancellable, locked_paths, locked, error); + want = 1; + if (flags & SECRET_SEARCH_ALL) + want = G_MAXINT; + have = 0; + + /* Remember, we're adding to the list backwards */ + + if (unlocked_paths) { + ret = service_load_items_sync (self, cancellable, unlocked_paths, + &unlocked, want, &have, error); + } + + if (ret && locked_paths) { + ret = service_load_items_sync (self, cancellable, locked_paths, + &locked, want, &have, error); + } g_strfreev (unlocked_paths); g_strfreev (locked_paths); - return ret; + if (!ret) { + g_list_free_full (unlocked, g_object_unref); + g_list_free_full (locked, g_object_unref); + return NULL; + } + + /* The lists are backwards at this point ... */ + items = g_list_concat (items, g_list_copy (locked)); + items = g_list_concat (items, g_list_copy (unlocked)); + items = g_list_reverse (items); + + if (flags & SECRET_SEARCH_UNLOCK) + secret_service_unlock_sync (self, locked, cancellable, NULL, NULL); + + if (flags & SECRET_SEARCH_LOAD_SECRETS) + secret_item_load_secrets_sync (items, NULL, NULL); + + g_list_free (locked); + g_list_free (unlocked); + return items; } SecretValue * diff --git a/library/secret-service.h b/library/secret-service.h index b3afcae..cb221e4 100644 --- a/library/secret-service.h +++ b/library/secret-service.h @@ -30,11 +30,18 @@ G_BEGIN_DECLS typedef enum { - SECRET_SERVICE_NONE, + SECRET_SERVICE_NONE = 0, SECRET_SERVICE_OPEN_SESSION = 1 << 1, SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2, } SecretServiceFlags; +typedef enum { + SECRET_SEARCH_NONE = 0, + SECRET_SEARCH_ALL = 1 << 1, + SECRET_SEARCH_UNLOCK = 1 << 2, + SECRET_SEARCH_LOAD_SECRETS = 1 << 3, +} SecretSearchFlags; + #define SECRET_TYPE_SERVICE (secret_service_get_type ()) #define SECRET_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_SERVICE, SecretService)) #define SECRET_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), SECRET_TYPE_SERVICE, SecretServiceClass)) @@ -145,21 +152,19 @@ gboolean secret_service_ensure_collections_sync (SecretService void secret_service_search (SecretService *self, GHashTable *attributes, + SecretSearchFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); -gboolean secret_service_search_finish (SecretService *self, +GList * secret_service_search_finish (SecretService *self, GAsyncResult *result, - GList **unlocked, - GList **locked, GError **error); -gboolean secret_service_search_sync (SecretService *self, +GList * secret_service_search_sync (SecretService *self, GHashTable *attributes, + SecretSearchFlags flags, GCancellable *cancellable, - GList **unlocked, - GList **locked, GError **error); void secret_service_lock (SecretService *self, diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c index b52ab58..f725b5a 100644 --- a/library/tests/test-methods.c +++ b/library/tests/test-methods.c @@ -121,29 +121,22 @@ test_search_sync (Test *test, gconstpointer used) { GHashTable *attributes; - gboolean ret; - GList *locked; - GList *unlocked; GError *error = NULL; + GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); - ret = secret_service_search_sync (test->service, attributes, NULL, - &unlocked, &locked, &error); + items = secret_service_search_sync (test->service, attributes, SECRET_SEARCH_NONE, + NULL, &error); g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (locked->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); - - g_assert (unlocked != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (unlocked->data), ==, "/org/freedesktop/secrets/collection/english/1"); - - g_list_free_full (unlocked, g_object_unref); - g_list_free_full (locked, g_object_unref); - g_hash_table_unref (attributes); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + + g_assert (items->next == NULL); + g_list_free_full (items, g_object_unref); } static void @@ -152,109 +145,243 @@ test_search_async (Test *test, { GAsyncResult *result = NULL; GHashTable *attributes; - gboolean ret; - GList *locked; - GList *unlocked; GError *error = NULL; + GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); - secret_service_search (test->service, attributes, NULL, - on_complete_get_result, &result); + secret_service_search (test->service, attributes, SECRET_SEARCH_NONE, NULL, + on_complete_get_result, &result); + g_hash_table_unref (attributes); + g_assert (result == NULL); + egg_test_wait (); g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_finish (test->service, result, - &unlocked, &locked, - &error); + items = secret_service_search_finish (test->service, result, &error); g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (locked != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (locked->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); - - g_assert (unlocked != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (unlocked->data), ==, "/org/freedesktop/secrets/collection/english/1"); - - g_list_free_full (unlocked, g_object_unref); - g_list_free_full (locked, g_object_unref); g_object_unref (result); - g_hash_table_unref (attributes); + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + + g_assert (items->next == NULL); + g_list_free_full (items, g_object_unref); } static void -test_search_nulls (Test *test, +test_search_all_sync (Test *test, + gconstpointer used) +{ + GHashTable *attributes; + GError *error = NULL; + GList *items; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + items = secret_service_search_sync (test->service, attributes, SECRET_SEARCH_ALL, + NULL, &error); + g_assert_no_error (error); + g_hash_table_unref (attributes); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + g_assert (secret_item_get_secret (items->data) == NULL); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == TRUE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); +} + +static void +test_search_all_async (Test *test, gconstpointer used) { GAsyncResult *result = NULL; GHashTable *attributes; - gboolean ret; - GList *items; GError *error = NULL; + GList *items; attributes = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (attributes, "number", "1"); - ret = secret_service_search_sync (test->service, attributes, NULL, - &items, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (items != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); - g_list_free_full (items, g_object_unref); - - ret = secret_service_search_sync (test->service, attributes, NULL, - NULL, &items, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (items != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); - g_list_free_full (items, g_object_unref); - - ret = secret_service_search_sync (test->service, attributes, NULL, - NULL, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - secret_service_search (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_finish (test->service, result, - &items, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (items != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); - g_list_free_full (items, g_object_unref); - g_clear_object (&result); - - secret_service_search (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_finish (test->service, result, - NULL, &items, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_assert (items != NULL); - g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); - g_list_free_full (items, g_object_unref); - g_clear_object (&result); - - secret_service_search (test->service, attributes, NULL, - on_complete_get_result, &result); - egg_test_wait (); - g_assert (G_IS_ASYNC_RESULT (result)); - ret = secret_service_search_finish (test->service, result, - NULL, NULL, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - g_clear_object (&result); - + secret_service_search (test->service, attributes, SECRET_SEARCH_ALL, NULL, + on_complete_get_result, &result); g_hash_table_unref (attributes); + g_assert (result == NULL); + + egg_test_wait (); + + g_assert (G_IS_ASYNC_RESULT (result)); + items = secret_service_search_finish (test->service, result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + g_assert (secret_item_get_secret (items->data) == NULL); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == TRUE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); +} + +static void +test_search_unlock_sync (Test *test, + gconstpointer used) +{ + GHashTable *attributes; + GError *error = NULL; + GList *items; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + items = secret_service_search_sync (test->service, attributes, + SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK, + NULL, &error); + g_assert_no_error (error); + g_hash_table_unref (attributes); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + g_assert (secret_item_get_secret (items->data) == NULL); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == FALSE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); +} + +static void +test_search_unlock_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GHashTable *attributes; + GError *error = NULL; + GList *items; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + secret_service_search (test->service, attributes, + SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK, NULL, + on_complete_get_result, &result); + g_hash_table_unref (attributes); + g_assert (result == NULL); + + egg_test_wait (); + + g_assert (G_IS_ASYNC_RESULT (result)); + items = secret_service_search_finish (test->service, result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + g_assert (secret_item_get_secret (items->data) == NULL); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == FALSE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); +} + +static void +test_search_secrets_sync (Test *test, + gconstpointer used) +{ + GHashTable *attributes; + GError *error = NULL; + SecretValue *value; + GList *items; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + items = secret_service_search_sync (test->service, attributes, + SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS, + NULL, &error); + g_assert_no_error (error); + g_hash_table_unref (attributes); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + value = secret_item_get_secret (items->data); + g_assert (value != NULL); + secret_value_unref (value); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == TRUE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); +} + +static void +test_search_secrets_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GHashTable *attributes; + GError *error = NULL; + SecretValue *value; + GList *items; + + attributes = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (attributes, "number", "1"); + + secret_service_search (test->service, attributes, + SECRET_SEARCH_ALL | SECRET_SEARCH_LOAD_SECRETS, NULL, + on_complete_get_result, &result); + g_hash_table_unref (attributes); + g_assert (result == NULL); + + egg_test_wait (); + + g_assert (G_IS_ASYNC_RESULT (result)); + items = secret_service_search_finish (test->service, result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert (items != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->data), ==, "/org/freedesktop/secrets/collection/english/1"); + g_assert (secret_item_get_locked (items->data) == FALSE); + value = secret_item_get_secret (items->data); + g_assert (value != NULL); + secret_value_unref (value); + + g_assert (items->next != NULL); + g_assert_cmpstr (g_dbus_proxy_get_object_path (items->next->data), ==, "/org/freedesktop/secrets/collection/spanish/10"); + g_assert (secret_item_get_locked (items->next->data) == TRUE); + g_assert (secret_item_get_secret (items->next->data) == NULL); + + g_assert (items->next->next == NULL); + g_list_free_full (items, g_object_unref); } static void @@ -826,7 +953,12 @@ main (int argc, char **argv) g_test_add ("/service/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); g_test_add ("/service/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); - g_test_add ("/service/search-nulls", Test, "mock-service-normal.py", setup, test_search_nulls, teardown); + g_test_add ("/service/search-all-sync", Test, "mock-service-normal.py", setup, test_search_all_sync, teardown); + g_test_add ("/service/search-all-async", Test, "mock-service-normal.py", setup, test_search_all_async, teardown); + g_test_add ("/service/search-unlock-sync", Test, "mock-service-normal.py", setup, test_search_unlock_sync, teardown); + g_test_add ("/service/search-unlock-async", Test, "mock-service-normal.py", setup, test_search_unlock_async, teardown); + g_test_add ("/service/search-secrets-sync", Test, "mock-service-normal.py", setup, test_search_secrets_sync, teardown); + g_test_add ("/service/search-secrets-async", Test, "mock-service-normal.py", setup, test_search_secrets_async, teardown); g_test_add ("/service/lock-sync", Test, "mock-service-lock.py", setup, test_lock_sync, teardown);