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.
This commit is contained in:
Stef Walter 2012-07-05 19:08:09 +02:00
parent 9c44ab0fa2
commit 889f6d66b7
4 changed files with 441 additions and 190 deletions

View File

@ -186,6 +186,7 @@ secret_service_ensure_session_sync
secret_service_ensure_collections secret_service_ensure_collections
secret_service_ensure_collections_finish secret_service_ensure_collections_finish
secret_service_ensure_collections_sync secret_service_ensure_collections_sync
SecretSearchFlags
secret_service_search secret_service_search
secret_service_search_finish secret_service_search_finish
secret_service_search_sync secret_service_search_sync
@ -219,9 +220,11 @@ SECRET_IS_SERVICE_CLASS
SECRET_SERVICE SECRET_SERVICE
SECRET_SERVICE_CLASS SECRET_SERVICE_CLASS
SECRET_SERVICE_GET_CLASS SECRET_SERVICE_GET_CLASS
SECRET_TYPE_SEARCH_FLAGS
SECRET_TYPE_SERVICE SECRET_TYPE_SERVICE
SECRET_TYPE_SERVICE_FLAGS SECRET_TYPE_SERVICE_FLAGS
SecretServicePrivate SecretServicePrivate
secret_search_flags_get_type
secret_service_flags_get_type secret_service_flags_get_type
secret_service_get_type secret_service_get_type
</SECTION> </SECTION>

View File

@ -25,17 +25,20 @@
#include "secret-value.h" #include "secret-value.h"
typedef struct { typedef struct {
SecretService *service;
GCancellable *cancellable; GCancellable *cancellable;
GHashTable *items; GHashTable *items;
gchar **unlocked; gchar **unlocked;
gchar **locked; gchar **locked;
guint loading; guint loading;
SecretSearchFlags flags;
} SearchClosure; } SearchClosure;
static void static void
search_closure_free (gpointer data) search_closure_free (gpointer data)
{ {
SearchClosure *closure = data; SearchClosure *closure = data;
g_object_unref (closure->service);
g_clear_object (&closure->cancellable); g_clear_object (&closure->cancellable);
g_hash_table_unref (closure->items); g_hash_table_unref (closure->items);
g_strfreev (closure->unlocked); g_strfreev (closure->unlocked);
@ -51,6 +54,64 @@ search_closure_take_item (SearchClosure *closure,
g_hash_table_insert (closure->items, (gpointer)path, item); 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 static void
on_search_loaded (GObject *source, on_search_loaded (GObject *source,
GAsyncResult *result, GAsyncResult *result,
@ -60,6 +121,7 @@ on_search_loaded (GObject *source,
SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res); SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GError *error = NULL; GError *error = NULL;
SecretItem *item; SecretItem *item;
GList *items;
closure->loading--; closure->loading--;
@ -69,8 +131,29 @@ on_search_loaded (GObject *source,
if (item != NULL) if (item != NULL)
search_closure_take_item (closure, item); 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); g_object_unref (res);
} }
@ -100,24 +183,32 @@ on_search_paths (GObject *source,
{ {
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res); SearchClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
SecretService *self = SECRET_SERVICE (source); SecretService *self = closure->service;
GError *error = NULL; GError *error = NULL;
gint want = 1;
guint i; guint i;
if (!secret_service_search_for_paths_finish (self, result, &closure->unlocked, secret_service_search_for_paths_finish (self, result, &closure->unlocked,
&closure->locked, &error)) { &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_take_error (res, error);
g_simple_async_result_complete (res); 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); g_object_unref (res);
} }
@ -125,6 +216,7 @@ on_search_paths (GObject *source,
* secret_service_search: * secret_service_search:
* @self: the secret service * @self: the secret service
* @attributes: (element-type utf8 utf8): search for items matching these attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @flags: search option flags
* @cancellable: optional cancellation object * @cancellable: optional cancellation object
* @callback: called when the operation completes * @callback: called when the operation completes
* @user_data: data to pass to the callback * @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. * Search for items matching the @attributes. All collections are searched.
* The @attributes should be a table of string keys and string values. * 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() * If %SECRET_SEARCH_UNLOCK is set in @flags, then items will be unlocked
* to get the results of this function. #SecretItem proxy objects will be * if necessary. In either case, locked and unlocked items will match the
* returned. If you prefer to only have the items D-Bus object paths returned, * search and be returned. If the unlock fails, the search does not fail.
* then then use the secret_service_search_for_paths() function. *
* 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 void
secret_service_search (SecretService *self, secret_service_search (SecretService *self,
GHashTable *attributes, GHashTable *attributes,
SecretSearchFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
@ -156,8 +255,10 @@ secret_service_search (SecretService *self,
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
secret_service_search); secret_service_search);
closure = g_slice_new0 (SearchClosure); closure = g_slice_new0 (SearchClosure);
closure->service = g_object_ref (self);
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; 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->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); g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free);
secret_service_search_for_paths (self, attributes, cancellable, secret_service_search_for_paths (self, attributes, cancellable,
@ -166,53 +267,25 @@ secret_service_search (SecretService *self,
g_object_unref (res); 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: * secret_service_search_finish:
* @self: the secret service * @self: the secret service
* @result: asynchronous result passed to callback * @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 * @error: location to place error on failure
* *
* Complete asynchronous operation to search for items. * Complete asynchronous operation to search for items.
* *
* Matching items that are locked or unlocked are placed in the @locked or * Returns: (transfer full) (element-type Secret.Item):
* @unlocked lists respectively. * a list of items that matched the search
*
* #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
*/ */
gboolean GList *
secret_service_search_finish (SecretService *self, secret_service_search_finish (SecretService *self,
GAsyncResult *result, GAsyncResult *result,
GList **unlocked,
GList **locked,
GError **error) GError **error)
{ {
GSimpleAsyncResult *res; GSimpleAsyncResult *res;
SearchClosure *closure; SearchClosure *closure;
GList *items;
g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@ -225,12 +298,11 @@ secret_service_search_finish (SecretService *self,
return FALSE; return FALSE;
closure = g_simple_async_result_get_op_res_gpointer (res); closure = g_simple_async_result_get_op_res_gpointer (res);
if (unlocked) if (closure->unlocked)
*unlocked = search_finish_build (closure->unlocked, closure); items = search_closure_build_items (closure, closure->unlocked);
if (locked) if (closure->locked)
*locked = search_finish_build (closure->locked, closure); items = g_list_concat (items, search_closure_build_items (closure, closure->locked));
return items;
return TRUE;
} }
static gboolean static gboolean
@ -238,26 +310,27 @@ service_load_items_sync (SecretService *self,
GCancellable *cancellable, GCancellable *cancellable,
gchar **paths, gchar **paths,
GList **items, GList **items,
gint want,
gint *have,
GError **error) GError **error)
{ {
SecretItem *item; SecretItem *item;
GList *result = NULL;
guint i; 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]); item = _secret_service_find_item_instance (self, paths[i]);
if (item == NULL) if (item == NULL)
item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE, item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE,
cancellable, error); cancellable, error);
if (item == NULL) { if (item == NULL) {
g_list_free_full (result, g_object_unref);
return FALSE; return FALSE;
} else { } else {
result = g_list_prepend (result, item); *items = g_list_prepend (*items, item);
(*have)++;
} }
} }
*items = g_list_reverse (result);
return TRUE; return TRUE;
} }
@ -265,60 +338,98 @@ service_load_items_sync (SecretService *self,
* secret_service_search_sync: * secret_service_search_sync:
* @self: the secret service * @self: the secret service
* @attributes: (element-type utf8 utf8): search for items matching these attributes * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @flags: search option flags
* @cancellable: optional cancellation object * @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 * @error: location to place error on failure
* *
* Search for items matching the @attributes. All collections are searched. * Search for items matching the @attributes. All collections are searched.
* The @attributes should be a table of string keys and string values. * 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 * This function may block indefinetely. Use the asynchronous version
* in user interface threads. * in user interface threads.
* *
* Matching items that are locked or unlocked are placed * Returns: (transfer full) (element-type Secret.Item):
* in the @locked or @unlocked lists respectively. * a list of items that matched the search
*
* #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
*/ */
gboolean GList *
secret_service_search_sync (SecretService *self, secret_service_search_sync (SecretService *self,
GHashTable *attributes, GHashTable *attributes,
SecretSearchFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GList **unlocked,
GList **locked,
GError **error) GError **error)
{ {
gchar **unlocked_paths = NULL; gchar **unlocked_paths = NULL;
gchar **locked_paths = NULL; gchar **locked_paths = NULL;
GList *items = NULL;
GList *locked = NULL;
GList *unlocked = NULL;
gboolean ret; gboolean ret;
gint want;
gint have;
g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (!secret_service_search_for_paths_sync (self, attributes, cancellable, if (!secret_service_search_for_paths_sync (self, attributes, cancellable,
unlocked ? &unlocked_paths : NULL, &unlocked_paths, &locked_paths, error))
locked ? &locked_paths : NULL, error)) return NULL;
return FALSE;
ret = TRUE; ret = TRUE;
if (unlocked) want = 1;
ret = service_load_items_sync (self, cancellable, unlocked_paths, unlocked, error); if (flags & SECRET_SEARCH_ALL)
if (ret && locked) want = G_MAXINT;
ret = service_load_items_sync (self, cancellable, locked_paths, locked, error); 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 (unlocked_paths);
g_strfreev (locked_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 * SecretValue *

View File

@ -30,11 +30,18 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { typedef enum {
SECRET_SERVICE_NONE, SECRET_SERVICE_NONE = 0,
SECRET_SERVICE_OPEN_SESSION = 1 << 1, SECRET_SERVICE_OPEN_SESSION = 1 << 1,
SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2, SECRET_SERVICE_LOAD_COLLECTIONS = 1 << 2,
} SecretServiceFlags; } 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_TYPE_SERVICE (secret_service_get_type ())
#define SECRET_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), SECRET_TYPE_SERVICE, SecretService)) #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)) #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, void secret_service_search (SecretService *self,
GHashTable *attributes, GHashTable *attributes,
SecretSearchFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
gboolean secret_service_search_finish (SecretService *self, GList * secret_service_search_finish (SecretService *self,
GAsyncResult *result, GAsyncResult *result,
GList **unlocked,
GList **locked,
GError **error); GError **error);
gboolean secret_service_search_sync (SecretService *self, GList * secret_service_search_sync (SecretService *self,
GHashTable *attributes, GHashTable *attributes,
SecretSearchFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GList **unlocked,
GList **locked,
GError **error); GError **error);
void secret_service_lock (SecretService *self, void secret_service_lock (SecretService *self,

View File

@ -121,29 +121,22 @@ test_search_sync (Test *test,
gconstpointer used) gconstpointer used)
{ {
GHashTable *attributes; GHashTable *attributes;
gboolean ret;
GList *locked;
GList *unlocked;
GError *error = NULL; GError *error = NULL;
GList *items;
attributes = g_hash_table_new (g_str_hash, g_str_equal); attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "number", "1"); g_hash_table_insert (attributes, "number", "1");
ret = secret_service_search_sync (test->service, attributes, NULL, items = secret_service_search_sync (test->service, attributes, SECRET_SEARCH_NONE,
&unlocked, &locked, &error); NULL, &error);
g_assert_no_error (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_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 static void
@ -152,109 +145,243 @@ test_search_async (Test *test,
{ {
GAsyncResult *result = NULL; GAsyncResult *result = NULL;
GHashTable *attributes; GHashTable *attributes;
gboolean ret;
GList *locked;
GList *unlocked;
GError *error = NULL; GError *error = NULL;
GList *items;
attributes = g_hash_table_new (g_str_hash, g_str_equal); attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "number", "1"); g_hash_table_insert (attributes, "number", "1");
secret_service_search (test->service, attributes, NULL, secret_service_search (test->service, attributes, SECRET_SEARCH_NONE, NULL,
on_complete_get_result, &result); on_complete_get_result, &result);
g_hash_table_unref (attributes);
g_assert (result == NULL);
egg_test_wait (); egg_test_wait ();
g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_ASYNC_RESULT (result));
ret = secret_service_search_finish (test->service, result, items = secret_service_search_finish (test->service, result, &error);
&unlocked, &locked,
&error);
g_assert_no_error (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_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 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) gconstpointer used)
{ {
GAsyncResult *result = NULL; GAsyncResult *result = NULL;
GHashTable *attributes; GHashTable *attributes;
gboolean ret;
GList *items;
GError *error = NULL; GError *error = NULL;
GList *items;
attributes = g_hash_table_new (g_str_hash, g_str_equal); attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "number", "1"); g_hash_table_insert (attributes, "number", "1");
ret = secret_service_search_sync (test->service, attributes, NULL, secret_service_search (test->service, attributes, SECRET_SEARCH_ALL, NULL,
&items, NULL, &error); on_complete_get_result, &result);
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);
g_hash_table_unref (attributes); 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 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-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-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); g_test_add ("/service/lock-sync", Test, "mock-service-lock.py", setup, test_lock_sync, teardown);