summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@src.gnome.org>2018-10-19 08:33:49 +0200
committerDaiki Ueno <dueno@src.gnome.org>2018-10-19 12:00:45 +0200
commit7716449b1ddfec4dea0f226cad7daa473f07772d (patch)
treeda65a3fb2baf5f4348ac19419c4e961775ac12ea
parent5ce2540785644a7f828dcafdec95c512c65abe5e (diff)
downloadlibsecret-7716449b1ddfec4dea0f226cad7daa473f07772d.tar.gz
password: Add secret_password_search* functions
Previously there were no functions in the simple API that return the matched attributes other than the secret value, while there were needs for augumenting user input with additional information (such as completing web forms). This adds a set of functions which wrap secret_service_search*. Note that the return value is a list of GHashTable not of SecretItem, because SecretItem is a subclass of GDBusProxy, which we don't want to expose from the simple API. Fixes #16
-rw-r--r--libsecret/secret-password.c225
-rw-r--r--libsecret/secret-password.h29
-rw-r--r--libsecret/secret-service.h7
-rw-r--r--libsecret/secret-types.h7
-rw-r--r--libsecret/test-password.c88
5 files changed, 349 insertions, 7 deletions
diff --git a/libsecret/secret-password.c b/libsecret/secret-password.c
index 149995d..4e388e1 100644
--- a/libsecret/secret-password.c
+++ b/libsecret/secret-password.c
@@ -845,6 +845,231 @@ secret_password_clearv_sync (const SecretSchema *schema,
}
/**
+ * 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.18.7
+ */
+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.18.7
+ */
+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 GHashTable): a list of hash tables containing attributes of the matched items
+ * Since: 0.18.7
+ */
+GList *
+secret_password_search_finish (GAsyncResult *result,
+ GError **error)
+{
+ GList *value;
+ GList *items = NULL;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ value = secret_service_search_finish (NULL, result, error);
+ while (value) {
+ SecretItem *item = SECRET_ITEM (value->data);
+ GHashTable *attributes = secret_item_get_attributes (item);
+ items = g_list_append (items, attributes);
+ g_object_unref (item);
+ value = g_list_delete_link (value, value);
+ }
+
+ return items;
+}
+
+/**
+ * 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 GHashTable): a list of hash tables containing attributes of the matched items
+ * Since: 0.18.7
+ */
+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 GHashTable): a list of hash tables containing attributes of the matched items
+ * Since: 0.18.7
+ */
+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 e35f415..d46705e 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 b745427..7e346c9 100644
--- a/libsecret/test-password.c
+++ b/libsecret/test-password.c
@@ -355,6 +355,90 @@ test_clear_no_name (Test *test,
}
static void
+free_attributes (gpointer data,
+ gpointer user_data)
+{
+ g_hash_table_unref ((GHashTable *)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)
{
secret_password_free (NULL);
@@ -381,6 +465,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 ();