diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt index 17ee05f..b561366 100644 --- a/docs/reference/libsecret/libsecret-sections.txt +++ b/docs/reference/libsecret/libsecret-sections.txt @@ -133,6 +133,11 @@ secret_password_clearv secret_password_clear_finish secret_password_clear_sync secret_password_clearv_sync +secret_password_search +secret_password_search_finish +secret_password_search_sync +secret_password_searchv +secret_password_searchv_sync secret_password_wipe secret_password_free diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c index 149995d..fc0ea0c 100644 --- a/libsecret/secret-password.c +++ b/libsecret/secret-password.c @@ -17,6 +17,7 @@ #include "secret-attributes.h" #include "secret-password.h" #include "secret-private.h" +#include "secret-retrievable.h" #include "secret-value.h" #include @@ -844,6 +845,225 @@ secret_password_clearv_sync (const SecretSchema *schema, return result; } +/** + * secret_password_search: (skip) + * @schema: the schema for the attributes + * @flags: search option flags + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * @...: the attribute keys and values, terminated with %NULL + * + * Search for items in 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. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_search (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) +{ + GHashTable *attributes; + va_list va; + + g_return_if_fail (schema != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + va_start (va, user_data); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return; + + secret_password_searchv (schema, attributes, flags, cancellable, + callback, user_data); + + g_hash_table_unref (attributes); +} + +/** + * secret_password_searchv: (rename-to secret_password_search) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): the attribute keys and values + * @flags: search option flags + * @cancellable: optional cancellation object + * @callback: called when the operation completes + * @user_data: data to be passed to the callback + * + * Search for items in the secret service. + * + * The @attributes should be a set of key and value string pairs. + * + * This method will return immediately and complete asynchronously. + * + * Since: 0.19.0 + */ +void +secret_password_searchv (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (schema != NULL); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + return; + + secret_service_search (NULL, schema, attributes, flags, + cancellable, callback, user_data); +} + +/** + * secret_password_search_finish: + * @result: the asynchronous result passed to the callback + * @error: location to place an error on failure + * + * Finish an asynchronous operation to search for items in the secret service. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_search_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return secret_service_search_finish (NULL, result, error); +} + +/** + * secret_password_search_sync: (skip) + * @schema: the schema for the attributes + * @flags: search option flags + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * @...: the attribute keys and values, terminated with %NULL + * + * Search for items in 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 attributes should be terminated with a %NULL. + * + * If no secret is found then %NULL is returned. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_search_sync (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error, + ...) +{ + GHashTable *attributes; + GList *items; + va_list va; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + va_start (va, error); + attributes = secret_attributes_buildv (schema, va); + va_end (va); + + /* Precondition failed, already warned */ + if (!attributes) + return NULL; + + items = secret_password_searchv_sync (schema, attributes, flags, + cancellable, error); + + g_hash_table_unref (attributes); + + return items; +} + +/** + * secret_password_searchv_sync: (rename-to secret_password_search_sync) + * @schema: the schema for attributes + * @attributes: (element-type utf8 utf8): the attribute keys and values + * @flags: search option flags + * @cancellable: optional cancellation object + * @error: location to place an error on failure + * + * Search for items in the secret service. + * + * The @attributes should be a set of key and value string pairs. + * + * If no secret is found then %NULL is returned. + * + * This method may block indefinitely and should not be used in user interface + * threads. + * + * Returns: (transfer full) (element-type Secret.Retrievable): a list of + * #SecretRetrievable containing attributes of the matched items + * + * Since: 0.19.0 + */ +GList * +secret_password_searchv_sync (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error) +{ + SecretSync *sync; + GList *items; + + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (attributes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* Warnings raised already */ + if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, TRUE)) + return NULL; + + sync = _secret_sync_new (); + g_main_context_push_thread_default (sync->context); + + secret_password_searchv (schema, attributes, flags, cancellable, + _secret_sync_on_result, sync); + + g_main_loop_run (sync->loop); + + items = secret_password_search_finish (sync->result, error); + + g_main_context_pop_thread_default (sync->context); + _secret_sync_free (sync); + + return items; +} + /** * secret_password_free: (skip) * @password: (allow-none): password to free diff --git a/libsecret/secret-password.h b/libsecret/secret-password.h index d47abb3..725d11b 100644 --- a/libsecret/secret-password.h +++ b/libsecret/secret-password.h @@ -126,6 +126,35 @@ gboolean secret_password_clearv_sync (const SecretSchema *sche GCancellable *cancellable, GError **error); +void secret_password_search (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + ...) G_GNUC_NULL_TERMINATED; + +void secret_password_searchv (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GList * secret_password_search_sync (const SecretSchema *schema, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error, + ...) G_GNUC_NULL_TERMINATED; + +GList * secret_password_searchv_sync (const SecretSchema *schema, + GHashTable *attributes, + SecretSearchFlags flags, + GCancellable *cancellable, + GError **error); + +GList * secret_password_search_finish (GAsyncResult *result, + GError **error); + void secret_password_free (gchar *password); void secret_password_wipe (gchar *password); diff --git a/libsecret/secret-service.h b/libsecret/secret-service.h index 4c3a827..44cbc1e 100644 --- a/libsecret/secret-service.h +++ b/libsecret/secret-service.h @@ -35,13 +35,6 @@ typedef enum { 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)) diff --git a/libsecret/secret-types.h b/libsecret/secret-types.h index 708c53f..cbbd3b1 100644 --- a/libsecret/secret-types.h +++ b/libsecret/secret-types.h @@ -38,6 +38,13 @@ typedef enum { #define SECRET_COLLECTION_SESSION "session" +typedef enum { + SECRET_SEARCH_NONE = 0, + SECRET_SEARCH_ALL = 1 << 1, + SECRET_SEARCH_UNLOCK = 1 << 2, + SECRET_SEARCH_LOAD_SECRETS = 1 << 3, +} SecretSearchFlags; + G_END_DECLS #endif /* __G_SERVICE_H___ */ diff --git a/libsecret/test-password.c b/libsecret/test-password.c index cbfb561..01053eb 100644 --- a/libsecret/test-password.c +++ b/libsecret/test-password.c @@ -356,6 +356,90 @@ test_clear_no_name (Test *test, g_assert_true (ret); } +static void +free_attributes (gpointer data, + gpointer user_data) +{ + g_object_unref ((GObject *)data); +} + +static void +test_search_sync (Test *test, + gconstpointer used) +{ + GList *items; + GError *error = NULL; + + items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "even", FALSE, + "string", "one", + "number", 1, + NULL); + + g_assert_no_error (error); + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + +static void +test_search_async (Test *test, + gconstpointer used) +{ + GAsyncResult *result = NULL; + GError *error = NULL; + GList *items; + + secret_password_search (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, on_complete_get_result, &result, + "even", FALSE, + "string", "one", + "number", 1, + NULL); + g_assert (result == NULL); + + egg_test_wait (); + + items = secret_password_search_finish (result, &error); + g_assert_no_error (error); + g_object_unref (result); + + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + +static void +test_search_no_name (Test *test, + gconstpointer used) +{ + GError *error = NULL; + GList *items; + + /* should return null, because nothing with mock schema and 5 */ + items = secret_password_search_sync (&MOCK_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "number", 5, + NULL); + g_assert_no_error (error); + g_assert (items == NULL); + + /* should return an item, because we have a prime schema with 5, and flags not to match name */ + items = secret_password_search_sync (&NO_NAME_SCHEMA, SECRET_SEARCH_ALL, + NULL, &error, + "number", 5, + NULL); + + g_assert_no_error (error); + g_assert_cmpint (g_list_length (items), ==, 1); + + g_list_foreach (items, free_attributes, NULL); + g_list_free (items); +} + static void test_password_free_null (void) { @@ -380,6 +464,10 @@ main (int argc, char **argv) g_test_add ("/password/delete-async", Test, "mock-service-delete.py", setup, test_delete_async, teardown); g_test_add ("/password/clear-no-name", Test, "mock-service-delete.py", setup, test_clear_no_name, teardown); + g_test_add ("/password/search-sync", Test, "mock-service-normal.py", setup, test_search_sync, teardown); + g_test_add ("/password/search-async", Test, "mock-service-normal.py", setup, test_search_async, teardown); + g_test_add ("/password/search-no-name", Test, "mock-service-normal.py", setup, test_search_no_name, teardown); + g_test_add_func ("/password/free-null", test_password_free_null); return egg_tests_run_with_loop ();