diff --git a/library/secret-methods.c b/library/secret-methods.c index 75af012..3393408 100644 --- a/library/secret-methods.c +++ b/library/secret-methods.c @@ -1487,8 +1487,8 @@ typedef struct { GCancellable *cancellable; SecretService *service; GVariant *attributes; - SecretPrompt *prompt; - gboolean deleted; + gint deleted; + gint deleting; } DeleteClosure; static void @@ -1498,7 +1498,6 @@ delete_closure_free (gpointer data) if (closure->service) g_object_unref (closure->service); g_variant_unref (closure->attributes); - g_clear_object (&closure->prompt); g_clear_object (&closure->cancellable); g_slice_free (DeleteClosure, closure); } @@ -1511,12 +1510,18 @@ on_delete_password_complete (GObject *source, GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; + gboolean deleted; - closure->deleted = _secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error); + closure->deleting--; + + deleted = _secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error); if (error != NULL) g_simple_async_result_take_error (res, error); + if (deleted) + closure->deleted++; - g_simple_async_result_complete (res); + if (closure->deleting <= 0) + g_simple_async_result_complete (res); g_object_unref (res); } @@ -1528,39 +1533,27 @@ on_delete_searched (GObject *source, { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - const gchar *path = NULL; GError *error = NULL; - gchar **locked; - gchar **unlocked; + gchar **unlocked = NULL; + gint i; - secret_service_search_for_dbus_paths_finish (SECRET_SERVICE (source), result, &unlocked, &locked, &error); - if (error != NULL) { - g_simple_async_result_take_error (res, error); - g_simple_async_result_complete (res); - - } else { - /* Choose the first path */ - if (unlocked && unlocked[0]) - path = unlocked[0]; - else if (locked && locked[0]) - path = locked[0]; - - /* Nothing to delete? */ - if (path == NULL) { - closure->deleted = FALSE; - g_simple_async_result_complete (res); - - /* Delete the first path */ - } else { - closure->deleted = TRUE; - _secret_service_delete_path (closure->service, path, TRUE, + secret_service_search_for_dbus_paths_finish (SECRET_SERVICE (source), result, &unlocked, NULL, &error); + if (error == NULL) { + for (i = 0; unlocked[i] != NULL; i++) { + _secret_service_delete_path (closure->service, unlocked[i], TRUE, closure->cancellable, on_delete_password_complete, g_object_ref (res)); + closure->deleting++; } + + if (closure->deleting == 0) + g_simple_async_result_complete (res); + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); } - g_strfreev (locked); g_strfreev (unlocked); g_object_unref (res); } @@ -1639,6 +1632,9 @@ secret_service_remove (SecretService *service, g_variant_ref_sink (closure->attributes); g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free); + /* A double check to make sure we don't delete everything, should have been checked earlier */ + g_assert (g_variant_n_children (closure->attributes) > 0); + if (service == NULL) { secret_service_get (SECRET_SERVICE_NONE, cancellable, on_delete_service, g_object_ref (res)); @@ -1681,7 +1677,7 @@ secret_service_remove_finish (SecretService *service, return FALSE; closure = g_simple_async_result_get_op_res_gpointer (res); - return closure->deleted; + return closure->deleted > 0; } /** diff --git a/library/secret-password.c b/library/secret-password.c index 78a2157..f506596 100644 --- a/library/secret-password.c +++ b/library/secret-password.c @@ -684,7 +684,7 @@ secret_password_remove (const SecretSchema *schema, * * The @attributes should be a set of key and value string pairs. * - * If multiple items match the attributes, then only one will be deleted. + * All unlocked items that match the attributes will be deleted. * * This method will return immediately and complete asynchronously. * @@ -714,10 +714,10 @@ secret_password_removev (const SecretSchema *schema, * @result: the asynchronous result passed to the callback * @error: location to place an error on failure * - * Finish an asynchronous operation to remove a password from the secret + * Finish an asynchronous operation to remove passwords from the secret * service. * - * Returns: whether the removal was successful or not + * Returns: whether any passwords were removed */ gboolean secret_password_remove_finish (GAsyncResult *result, @@ -734,19 +734,19 @@ secret_password_remove_finish (GAsyncResult *result, * @error: location to place an error on failure * @...: the attribute keys and values, terminated with %NULL * - * Remove a password from the secret service. + * Remove passwords from the secret service. * * The variable argument list should contain pairs of a) The attribute name as * a null-terminated string, followed by b) attribute value, either a character * string, an int number, or a gboolean value, as defined in the password * @schema. The list of attribtues should be terminated with a %NULL. * - * If multiple items match the attributes, then only one will be deleted. + * All unlocked items that match the attributes will be deleted. * * This method may block indefinitely and should not be used in user interface * threads. * - * Returns: whether the removal was successful or not + * Returns: whether the any passwords were removed */ gboolean secret_password_remove_sync (const SecretSchema* schema, @@ -785,12 +785,12 @@ secret_password_remove_sync (const SecretSchema* schema, * * The @attributes should be a set of key and value string pairs. * - * If multiple items match the attributes, then only one will be deleted. + * All unlocked items that match the attributes will be deleted. * * This method may block indefinitely and should not be used in user interface * threads. * - * Returns: whether the removal was successful or not + * Returns: whether any passwords were removed * * Rename to: secret_password_remove_sync */ diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c index 9dc8214..8b77dbc 100644 --- a/library/tests/test-methods.c +++ b/library/tests/test-methods.c @@ -513,11 +513,12 @@ test_remove_locked (Test *test, "number", 3, NULL); + /* Locked items can't be removed via this API */ ret = secret_service_remove_sync (test->service, &MOCK_SCHEMA, attributes, NULL, &error); g_hash_table_unref (attributes); g_assert_no_error (error); - g_assert (ret == TRUE); + g_assert (ret == FALSE); } static void @@ -545,6 +546,7 @@ static void test_remove_no_name (Test *test, gconstpointer used) { + const gchar *paths[] = { "/org/freedesktop/secrets/collection/german", NULL }; GError *error = NULL; GHashTable *attributes; gboolean ret; @@ -558,6 +560,10 @@ test_remove_no_name (Test *test, g_assert_no_error (error); g_assert (ret == FALSE); + /* We need this collection unlocked for the next test */ + secret_service_unlock_dbus_paths_sync (test->service, paths, NULL, NULL, &error); + g_assert_no_error (error); + /* We have an item with 5 in prime schema, but should match anyway becase of flags */ ret = secret_service_remove_sync (test->service, &NO_NAME_SCHEMA, attributes, NULL, &error); g_assert_no_error (error); diff --git a/library/tests/test-password.c b/library/tests/test-password.c index d5829df..303fae7 100644 --- a/library/tests/test-password.c +++ b/library/tests/test-password.c @@ -15,6 +15,7 @@ #include "config.h" #include "secret-password.h" +#include "secret-paths.h" #include "secret-private.h" #include "mock-service.h" @@ -269,6 +270,8 @@ static void test_remove_no_name (Test *test, gconstpointer used) { + const gchar *paths[] = { "/org/freedesktop/secrets/collection/german", NULL }; + SecretService *service; GError *error = NULL; gboolean ret; @@ -279,6 +282,13 @@ test_remove_no_name (Test *test, g_assert_no_error (error); g_assert (ret == FALSE); + /* We need this collection unlocked for the next test */ + service = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error); + g_assert_no_error (error); + secret_service_unlock_dbus_paths_sync (service, paths, NULL, NULL, &error); + g_assert_no_error (error); + g_object_unref (service); + /* We have an item with 5 in prime schema, but should match anyway becase of flags */ ret = secret_password_remove_sync (&NO_NAME_SCHEMA, NULL, &error, "number", 5,