From 72dc330a0401e31b21160110ce98cbbb37cdfb81 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Mon, 16 Jan 2012 15:08:29 +0100 Subject: [PATCH] Complete the gsecret_password_xxx() API. --- library/gsecret-password.c | 359 ++++++++++++++++----- library/gsecret-password.h | 34 +- library/gsecret-private.h | 23 ++ library/gsecret-prompt.c | 19 +- library/gsecret-prompt.h | 3 +- library/gsecret-service.c | 602 +++++++++++++++++++++++++++++++++++- library/gsecret-service.h | 46 ++- library/gsecret-util.c | 119 +++++++ library/gsecret-value.c | 35 ++- library/gsecret-value.h | 6 +- library/tests/test-prompt.c | 8 +- 11 files changed, 1143 insertions(+), 111 deletions(-) diff --git a/library/gsecret-password.c b/library/gsecret-password.c index d504461..be54069 100644 --- a/library/gsecret-password.c +++ b/library/gsecret-password.c @@ -57,82 +57,70 @@ on_sync_result (GObject *source, g_main_loop_quit (closure->loop); } -#if 0 - typedef struct { - GVariant *properties; + const GSecretSchema *schema; + GHashTable *attributes; gchar *collection_path; - GSecretValue *secret; + gchar *label; + GSecretValue *value; GCancellable *cancellable; + gboolean created; } StoreClosure; static void store_closure_free (gpointer data) { StoreClosure *closure = data; - g_variant_unref (closure->properties); + g_hash_table_unref (closure->attributes); g_free (closure->collection_path); - gsecret_value_unref (closure->secret); - g_clear_object (closure->cancellable); - g_free (closure); + g_free (closure->label); + gsecret_value_unref (closure->value); + g_clear_object (&closure->cancellable); + g_slice_free (StoreClosure, closure); } static void -on_create_item_reply (GObject *source, - GAsyncResult *result, - gpointer user_data) +on_store_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GError *error = NULL; - retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (error == NULL) { - g_variant_get (retval, "(&o&o)", &item_path, &prompt_path); - if (prompt_path xxx) - gsecret_prompt_perform (self, "", closure->cancellable, - on_store_prompt_complete, NULL); - - if (g_strcmp0 (item_path, "/") != 0) - xxx complete! - } + closure->created = gsecret_service_store_password_finish (GSECRET_SERVICE (source), + result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); g_object_unref (res); } static void -on_store_service_connected (GObject *source, - GAsyncResult *result, - gpointer user_data) +on_store_connected (GObject *source, + GAsyncResult *result, + gpointer user_data) { GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); GSecretService *service; GError *error = NULL; - GDBusProxy *proxy; - GVariant *params; service = _gsecret_service_bare_connect_finish (result, &error); if (error == NULL) { - params = g_variant_new ("(&a{sv}&(oayays)b)", - closure->properties, - _gsecret_service_encode_secret (service, closure->secret), - TRUE); + gsecret_service_store_passwordv (service, closure->schema, + closure->attributes, + closure->collection_path, + closure->label, closure->value, + closure->cancellable, + on_store_complete, + g_object_ref (res)); + g_object_unref (service); - proxy = G_DBUS_PROXY (service); - g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), - g_dbus_proxy_get_name (proxy), - closure->collection_path, - GSECRET_COLLECTION_INTERFACE, - "CreateItem", params, G_VARIANT_TYPE ("(oo)"), - G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, - closure->cancellable, on_create_item_reply, - g_object_ref (res)); } else { g_simple_async_result_take_error (res, error); g_simple_async_result_complete (res); - - - } g_object_unref (res); @@ -148,107 +136,332 @@ gsecret_password_store (const GSecretSchema *schema, gpointer user_data, ...) { - GSimpleAsyncResult *res; - GVariant *attributes; - StoreClosure *closure; - GVariantBuilder builder; + GHashTable *attributes; va_list va; g_return_if_fail (schema != NULL); + g_return_if_fail (collection_path != NULL); g_return_if_fail (label != NULL); g_return_if_fail (password != NULL); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - /* Build up the attributes */ va_start (va, user_data); - attributes = build_attributes (schema, va); + attributes = _gsecret_util_attributes_for_varargs (schema, va); va_end (va); - g_return_if_fail (attributes != NULL); - /* Build up the various properties */ - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Attributes", attributes); - g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Label", g_variant_new_string ("label")); - g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Schema", g_variant_new_string (schema->schema_name)); + gsecret_password_storev (schema, collection_path, label, password, attributes, + cancellable, callback, user_data); + + g_hash_table_unref (attributes); +} + +void +gsecret_password_storev (const GSecretSchema *schema, + const gchar *collection_path, + const gchar *label, + const gchar *password, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + StoreClosure *closure; + + g_return_if_fail (schema != NULL); + g_return_if_fail (collection_path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (password != NULL); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); res = g_simple_async_result_new (NULL, callback, user_data, - gsecret_password_store_finish); - closure = g_new0 (StoreClosure, 1); - closure->properties = g_variant_ref_sink (g_variant_builder_end (&builder)); + gsecret_password_storev); + closure = g_slice_new0 (StoreClosure); + closure->schema = schema; closure->collection_path = g_strdup (collection_path); - closure->secret = gsecret_value_new (password, -1, "text/plain"); + closure->label = g_strdup (label); + closure->value = gsecret_value_new (password, -1, "text/plain"); + closure->attributes = g_hash_table_ref (attributes); closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free); - _gsecret_service_bare_connect_with_session (cancellable, on_store_service_connected, - g_object_ref (res)); + _gsecret_service_bare_connect (NULL, TRUE, cancellable, + on_store_connected, g_object_ref (res)); g_object_unref (res); } -#if 0 gboolean gsecret_password_store_finish (GAsyncResult *result, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + GSimpleAsyncResult *res; + StoreClosure *closure; + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, + gsecret_password_storev), FALSE); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return FALSE; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return closure->created; } gboolean -gsecret_password_store_sync (const GSecretPasswordSchema *schema, - const gchar *collection, +gsecret_password_store_sync (const GSecretSchema *schema, + const gchar *collection_path, const gchar *label, const gchar *password, GCancellable *cancellable, GError **error, - const gchar *attribute_name, ...) { + GHashTable *attributes; + va_list va; + gboolean ret; + g_return_val_if_fail (schema != NULL, FALSE); - g_return_val_if_fail (display_name != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); g_return_val_if_fail (password != NULL, FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + va_start (va, error); + attributes = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + ret = gsecret_password_storev_sync (schema, collection_path, label, password, + attributes, cancellable, error); + + g_hash_table_unref (attributes); + return ret; +} + +gboolean +gsecret_password_storev_sync (const GSecretSchema *schema, + const gchar *collection_path, + const gchar *label, + const gchar *password, + GHashTable *attributes, + GCancellable *cancellable, + GError **error) +{ + SyncClosure *closure; + gboolean ret; + + g_return_val_if_fail (schema != NULL, FALSE); + g_return_val_if_fail (collection_path != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (password != NULL, FALSE); + g_return_val_if_fail (attributes != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + closure = sync_closure_new (); + g_main_context_push_thread_default (closure->context); + + gsecret_password_storev (schema, collection_path, label, password, attributes, + cancellable, on_sync_result, closure); + + g_main_loop_run (closure->loop); + + ret = gsecret_password_store_finish (closure->result, error); + + g_main_context_pop_thread_default (closure->context); + sync_closure_free (closure); + + return ret; +} + +typedef struct { + GCancellable *cancellable; + GHashTable *attributes; + GSecretValue *value; +} LookupClosure; + +static void +lookup_closure_free (gpointer data) +{ + LookupClosure *closure = data; + g_clear_object (&closure->cancellable); + g_hash_table_unref (closure->attributes); + if (closure->value) + gsecret_value_unref (closure->value); + g_slice_free (LookupClosure, closure); } void -gsecret_password_lookup (const GSecretPasswordSchema *schema, +gsecret_password_lookup (const GSecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, - const gchar *attribute_name, ...) { + 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 = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + gsecret_password_lookupv (attributes, cancellable, callback, user_data); + + g_hash_table_unref (attributes); +} + +static void +on_lookup_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + + closure->value = gsecret_service_lookup_password_finish (GSECRET_SERVICE (source), + result, &error); + + if (error != NULL) + g_simple_async_result_take_error (res, error); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_lookup_connected (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *service; + GError *error = NULL; + + service = _gsecret_service_bare_connect_finish (result, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else { + gsecret_service_lookup_passwordv (service, closure->attributes, closure->cancellable, + on_lookup_complete, g_object_ref (res)); + g_object_unref (service); + } + + g_object_unref (res); +} + +void +gsecret_password_lookupv (GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + LookupClosure *closure; + + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (NULL, callback, user_data, + gsecret_password_lookupv); + closure = g_slice_new0 (LookupClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free); + + _gsecret_service_bare_connect (NULL, TRUE, cancellable, + on_lookup_connected, g_object_ref (res)); + + g_object_unref (res); } gchar * gsecret_password_lookup_finish (GAsyncResult *result, GError **error) { - g_return_val_if_fail (error == NULL || *error == NULL, NULL); + GSimpleAsyncResult *res; + LookupClosure *closure; + const gchar *content_type; + gchar *password = NULL; + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, + gsecret_password_lookupv), NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + content_type = gsecret_value_get_content_type (closure->value); + if (content_type && g_str_equal (content_type, "text/plain")) { + password = _gsecret_value_unref_to_password (closure->value); + closure->value = NULL; + } + + return password; } gchar * -gsecret_password_lookup_sync (const GSecretPasswordSchema *schema, +gsecret_password_lookup_sync (const GSecretSchema *schema, GCancellable *cancellable, GError **error, - const gchar *attribute_name, ...) { + GHashTable *attributes; + gchar *password; + 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 = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + password = gsecret_password_lookupv_sync (attributes, cancellable, error); + + g_hash_table_unref (attributes); + + return password; } -#endif -#endif +gchar * +gsecret_password_lookupv_sync (GHashTable *attributes, + GCancellable *cancellable, + GError **error) +{ + SyncClosure *closure; + gchar *password; + + 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); + + closure = sync_closure_new (); + g_main_context_push_thread_default (closure->context); + + gsecret_password_deletev (attributes, cancellable, + on_sync_result, closure); + + g_main_loop_run (closure->loop); + + password = gsecret_password_lookup_finish (closure->result, error); + + g_main_context_pop_thread_default (closure->context); + sync_closure_free (closure); + + return password; +} typedef struct { GCancellable *cancellable; diff --git a/library/gsecret-password.h b/library/gsecret-password.h index 9ab2250..b0aefa4 100644 --- a/library/gsecret-password.h +++ b/library/gsecret-password.h @@ -19,8 +19,6 @@ G_BEGIN_DECLS #include "gsecret-types.h" -#if 0 - void gsecret_password_store (const GSecretSchema *schema, const gchar *collection_path, const gchar *label, @@ -30,23 +28,45 @@ void gsecret_password_store (const GSecretSchema *sc gpointer user_data, ...) G_GNUC_NULL_TERMINATED; +void gsecret_password_storev (const GSecretSchema *schema, + const gchar *collection_path, + const gchar *label, + const gchar *password, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean gsecret_password_store_finish (GAsyncResult *result, GError **error); -void gsecret_password_store_sync (const GSecretSchema *schema, - const gchar *collection, - const gchar *display_name, +gboolean gsecret_password_store_sync (const GSecretSchema *schema, + const gchar *collection_path, + const gchar *label, const gchar *password, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; +gboolean gsecret_password_storev_sync (const GSecretSchema *schema, + const gchar *collection_path, + const gchar *display_name, + const gchar *password, + GHashTable *attributes, + GCancellable *cancellable, + GError **error); + void gsecret_password_lookup (const GSecretSchema *schema, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; +void gsecret_password_lookupv (GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gchar * gsecret_password_lookup_finish (GAsyncResult *result, GError **error); @@ -55,7 +75,9 @@ gchar * gsecret_password_lookup_sync (const GSecretSchema *sc GError **error, ...) G_GNUC_NULL_TERMINATED; -#endif +gchar * gsecret_password_lookupv_sync (GHashTable *attributes, + GCancellable *cancellable, + GError **error); void gsecret_password_delete (const GSecretSchema *schema, GCancellable *cancellable, diff --git a/library/gsecret-private.h b/library/gsecret-private.h index 15b0b6b..8e5b620 100644 --- a/library/gsecret-private.h +++ b/library/gsecret-private.h @@ -51,9 +51,30 @@ gboolean _gsecret_util_empty_path (const gchar *pat GVariant * _gsecret_util_variant_for_attributes (GHashTable *attributes); +GHashTable * _gsecret_util_attributes_for_variant (GVariant *variant); + GHashTable * _gsecret_util_attributes_for_varargs (const GSecretSchema *schema, va_list va); +void _gsecret_util_set_property (GDBusProxy *proxy, + const gchar *property, + GVariant *value, + gpointer result_tag, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean _gsecret_util_set_property_finish (GDBusProxy *proxy, + gpointer result_tag, + GAsyncResult *result, + GError **error); + +gboolean _gsecret_util_set_property_sync (GDBusProxy *proxy, + const gchar *property, + GVariant *value, + GCancellable *cancellable, + GError **error); + void _gsecret_service_set_default_bus_name (const gchar *bus_name); GSecretService * _gsecret_service_bare_instance (GDBusConnection *connection, @@ -79,6 +100,8 @@ const gchar * _gsecret_service_ensure_session_finish (GSecretService * GCancellable **cancellable, GError **error); +gchar * _gsecret_value_unref_to_password (GSecretValue *value); + G_END_DECLS #endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-prompt.c b/library/gsecret-prompt.c index f1e34c6..60697fb 100644 --- a/library/gsecret-prompt.c +++ b/library/gsecret-prompt.c @@ -422,12 +422,23 @@ gsecret_prompt_perform_finish (GSecretPrompt *self, } GVariant * -gsecret_prompt_get_result_value (GSecretPrompt *self) +gsecret_prompt_get_result_value (GSecretPrompt *self, + const GVariantType *expected_type) { + gchar *string; + g_return_val_if_fail (GSECRET_IS_PROMPT (self), NULL); - if (self->pv->last_result) - return g_variant_ref (self->pv->last_result); + if (!self->pv->last_result) + return NULL; - return NULL; + if (expected_type && !g_variant_is_of_type (self->pv->last_result, expected_type)) { + string = g_variant_type_dup_string (expected_type); + g_warning ("received unexpected result type %s from Completed signal instead of expected %s", + g_variant_get_type_string (self->pv->last_result), string); + g_free (string); + return NULL; + } + + return g_variant_ref (self->pv->last_result); } diff --git a/library/gsecret-prompt.h b/library/gsecret-prompt.h index 7abfb93..59d2dd9 100644 --- a/library/gsecret-prompt.h +++ b/library/gsecret-prompt.h @@ -65,7 +65,8 @@ gboolean gsecret_prompt_perform_finish (GSecretPrompt *sel GAsyncResult *result, GError **error); -GVariant * gsecret_prompt_get_result_value (GSecretPrompt *self); +GVariant * gsecret_prompt_get_result_value (GSecretPrompt *self, + const GVariantType *expected_type); G_END_DECLS diff --git a/library/gsecret-service.c b/library/gsecret-service.c index 44c3e70..63144e5 100644 --- a/library/gsecret-service.c +++ b/library/gsecret-service.c @@ -1493,6 +1493,172 @@ gsecret_service_get_secrets_for_paths_sync (GSecretService *self, return values; } +typedef struct { + GCancellable *cancellable; + GSecretPrompt *prompt; + gint unlocked; +} UnlockClosure; + +static void +unlock_closure_free (gpointer data) +{ + UnlockClosure *closure = data; + g_clear_object (&closure->cancellable); + g_clear_object (&closure->prompt); + g_slice_free (UnlockClosure, closure); +} + +gint +gsecret_service_unlock_paths_sync (GSecretService *self, + const gchar **paths, + GCancellable *cancellable, + gchar ***unlocked, + GError **error) +{ + SyncClosure *closure; + gint count; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (paths != NULL, -1); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1); + g_return_val_if_fail (unlocked != NULL, -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + closure = sync_closure_new (); + g_main_context_push_thread_default (closure->context); + + gsecret_service_unlock_paths (self, paths, cancellable, + on_sync_result, closure); + + g_main_loop_run (closure->loop); + + count = gsecret_service_unlock_paths_finish (self, closure->result, + unlocked, error); + + g_main_context_pop_thread_default (closure->context); + sync_closure_free (closure); + + return count; +} + +static void +on_unlock_prompted (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + UnlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GVariant *retval; + GError *error = NULL; + gboolean ret; + + ret = gsecret_service_prompt_finish (self, result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + + if (ret) { + retval = gsecret_prompt_get_result_value (closure->prompt, G_VARIANT_TYPE ("ao")); + closure->unlocked = g_variant_n_children (retval); + g_variant_unref (retval); + } else { + closure->unlocked = 0; + } + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_unlock_called (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + UnlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (g_async_result_get_source_object (user_data)); + GError *error = NULL; + const gchar *prompt = NULL; + gchar **unlocked = NULL; + GVariant *retval; + + retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else { + g_variant_get (retval, "(^ao&o)", &unlocked, &prompt); + + if (_gsecret_util_empty_path (prompt)) { + closure->unlocked = g_strv_length (unlocked); + g_simple_async_result_complete (res); + + } else { + closure->prompt = gsecret_prompt_instance (self, prompt); + gsecret_service_prompt (self, closure->prompt, closure->cancellable, + on_unlock_prompted, g_object_ref (res)); + } + + g_strfreev (unlocked); + g_variant_unref (retval); + } + + g_object_unref (self); + g_object_unref (res); +} + +void +gsecret_service_unlock_paths (GSecretService *self, + const gchar **paths, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + UnlockClosure *closure; + + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (paths != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + gsecret_service_unlock_paths); + closure = g_slice_new (UnlockClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; + g_simple_async_result_set_op_res_gpointer (res, closure, unlock_closure_free); + + g_dbus_proxy_call (G_DBUS_PROXY (self), "Unlock", + g_variant_new ("(@ao)", g_variant_new_objv (paths, -1)), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, on_unlock_called, g_object_ref (res)); + + g_object_unref (res); +} + +gint +gsecret_service_unlock_paths_finish (GSecretService *self, + GAsyncResult *result, + gchar ***unlocked, + GError **error) +{ + GSimpleAsyncResult *res; + UnlockClosure *closure; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), -1); + g_return_val_if_fail (unlocked != NULL, -1); + g_return_val_if_fail (error == NULL || *error == NULL, -1); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + gsecret_service_unlock_paths), -1); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return -1; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return closure->unlocked; +} + gboolean gsecret_service_prompt_sync (GSecretService *self, GSecretPrompt *prompt, @@ -1568,20 +1734,166 @@ gsecret_service_prompt_finish (GSecretService *self, return (klass->prompt_finish) (self, result, error); } -#if 0 +typedef struct { + gchar *collection_path; + GSecretValue *value; + GCancellable *cancellable; + GSecretPrompt *prompt; + gboolean created; +} StoreClosure; + +static void +store_closure_free (gpointer data) +{ + StoreClosure *closure = data; + g_free (closure->collection_path); + gsecret_value_unref (closure->value); + g_clear_object (&closure->cancellable); + g_clear_object (&closure->prompt); + g_free (closure); +} void gsecret_service_store_password (GSecretService *self, const GSecretSchema *schema, const gchar *collection_path, const gchar *label, - const gchar *password, + GSecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) { + GHashTable *attributes; + va_list va; + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (schema != NULL); + g_return_if_fail (collection_path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (value != NULL); + + va_start (va, user_data); + attributes = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + gsecret_service_store_passwordv (self, schema, attributes, collection_path, + label, value, cancellable, callback, user_data); + + g_hash_table_unref (attributes); +} + +static void +on_store_prompt (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GError *error = NULL; + + closure->created = gsecret_service_prompt_finish (GSECRET_SERVICE (source), result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_store_create (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (g_async_result_get_source_object (result)); + const gchar *prompt_path = NULL; + const gchar *item_path = NULL; + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (error == NULL) { + g_variant_get (retval, "(&o&o)", &item_path, &prompt_path); + if (!_gsecret_util_empty_path (prompt_path)) { + closure->prompt = gsecret_prompt_instance (self, prompt_path); + gsecret_service_prompt (self, closure->prompt, closure->cancellable, + on_store_prompt, g_object_ref (res)); + + } else { + g_simple_async_result_complete (res); + } + + g_variant_unref (retval); + + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (self); + g_object_unref (res); +} + +void +gsecret_service_store_passwordv (GSecretService *self, + const GSecretSchema *schema, + GHashTable *attributes, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + GVariant *attrs; + StoreClosure *closure; + GVariantBuilder builder; + GVariant *params; + GDBusProxy *proxy; + + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (schema != NULL); + g_return_if_fail (attributes != NULL); + g_return_if_fail (collection_path != NULL); + g_return_if_fail (label != NULL); + g_return_if_fail (value != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + /* Build up the attributes */ + attrs = _gsecret_util_variant_for_attributes (attributes); + + /* Build up the various properties */ + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Attributes", attrs); + g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Label", g_variant_new_string (label)); + g_variant_builder_add (&builder, "{sv}", GSECRET_SERVICE_INTERFACE "Schema", g_variant_new_string (schema->schema_name)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + gsecret_service_store_passwordv); + closure = g_new0 (StoreClosure, 1); + closure->collection_path = g_strdup (collection_path); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free); + + params = g_variant_new ("(&a{sv}&(oayays)b)", + g_variant_builder_end (&builder), + _gsecret_service_encode_secret (self, value), + TRUE); + + proxy = G_DBUS_PROXY (self); + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + closure->collection_path, + GSECRET_COLLECTION_INTERFACE, + "CreateItem", params, G_VARIANT_TYPE ("(oo)"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + closure->cancellable, on_store_create, + g_object_ref (res)); + + g_object_unref (res); } gboolean @@ -1589,20 +1901,106 @@ gsecret_service_store_password_finish (GSecretService *self, GAsyncResult *result, GError **error) { + GSimpleAsyncResult *res; + StoreClosure *closure; + g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + gsecret_service_store_passwordv), FALSE); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (!g_simple_async_result_propagate_error (res, error)) + return FALSE; + + closure = g_simple_async_result_get_op_res_gpointer (res); + return closure->created; } -void +gboolean gsecret_service_store_password_sync (GSecretService *self, const GSecretSchema *schema, - const gchar *collection, - const gchar *display_name, - const gchar *password, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, GCancellable *cancellable, GError **error, ...) { + GHashTable *attributes; + gboolean ret; + va_list va; + g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (schema != NULL, FALSE); + g_return_val_if_fail (collection_path != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + va_start (va, error); + attributes = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + ret = gsecret_service_store_passwordv_sync (self, schema, attributes, collection_path, + label, value, cancellable, error); + + g_hash_table_unref (attributes); + + return ret; +} + +gboolean +gsecret_service_store_passwordv_sync (GSecretService *self, + const GSecretSchema *schema, + GHashTable *attributes, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, + GCancellable *cancellable, + GError **error) +{ + SyncClosure *closure; + gboolean ret; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE); + g_return_val_if_fail (schema != NULL, FALSE); + g_return_val_if_fail (attributes != NULL, FALSE); + g_return_val_if_fail (collection_path != NULL, FALSE); + g_return_val_if_fail (label != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + closure = sync_closure_new (); + g_main_context_push_thread_default (closure->context); + + gsecret_service_store_passwordv (self, schema, attributes, collection_path, + label, value, cancellable, on_sync_result, closure); + + g_main_loop_run (closure->loop); + + ret = gsecret_service_store_password_finish (self, closure->result, error); + + g_main_context_pop_thread_default (closure->context); + sync_closure_free (closure); + + return ret; +} + +typedef struct { + GSecretValue *value; + GCancellable *cancellable; +} LookupClosure; + +static void +lookup_closure_free (gpointer data) +{ + LookupClosure *closure = data; + gsecret_value_unref (closure->value); + g_clear_object (&closure->cancellable); + g_slice_free (LookupClosure, closure); } void @@ -1613,28 +2011,214 @@ gsecret_service_lookup_password (GSecretService *self, gpointer user_data, ...) { + GHashTable *attributes; + va_list va; + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (schema != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + va_start (va, user_data); + attributes = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + gsecret_service_lookup_passwordv (self, attributes, cancellable, callback, user_data); + + g_hash_table_unref (attributes); } -gchar * +static void +on_lookup_get_secret (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GError *error = NULL; + + closure->value = gsecret_service_get_secret_for_path_finish (self, result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_lookup_unlocked (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GError *error = NULL; + gchar **unlocked = NULL; + + gsecret_service_unlock_paths_finish (GSECRET_SERVICE (source), + result, &unlocked, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else if (unlocked && unlocked[0]) { + gsecret_service_get_secret_for_path (self, unlocked[0], + closure->cancellable, + on_lookup_get_secret, + g_object_ref (res)); + + } else { + g_simple_async_result_complete (res); + } + + g_strfreev (unlocked); + g_object_unref (res); +} + +static void +on_lookup_searched (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GError *error = NULL; + gchar **unlocked = NULL; + gchar **locked = NULL; + + gsecret_service_search_for_paths_finish (self, result, &unlocked, &locked, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else if (unlocked && unlocked[0]) { + gsecret_service_get_secret_for_path (self, unlocked[0], + closure->cancellable, + on_lookup_get_secret, + g_object_ref (res)); + + } else if (locked && locked[0]) { + const gchar *paths[] = { locked[0], NULL }; + gsecret_service_unlock_paths (self, paths, + closure->cancellable, + on_lookup_unlocked, + g_object_ref (res)); + + } else { + g_simple_async_result_complete (res); + } + + g_strfreev (unlocked); + g_strfreev (locked); + g_object_unref (res); +} + +void +gsecret_service_lookup_passwordv (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + LookupClosure *closure; + + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (attributes != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + gsecret_service_lookup_passwordv); + closure = g_slice_new0 (LookupClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free); + + gsecret_service_search_for_paths (self, attributes, cancellable, + on_lookup_searched, g_object_ref (res)); + + g_object_unref (res); +} + +GSecretValue * gsecret_service_lookup_password_finish (GSecretService *self, GAsyncResult *result, GError **error) { + GSimpleAsyncResult *res; + LookupClosure *closure; + GSecretValue *value; + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + gsecret_service_lookup_passwordv), NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (res); + value = closure->value; + closure->value = NULL; + return value; } -gchar * +GSecretValue * gsecret_service_lookup_password_sync (GSecretService *self, const GSecretSchema *schema, GCancellable *cancellable, GError **error, ...) { + GHashTable *attributes; + GSecretValue *value; + va_list va; + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (schema != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + + va_start (va, error); + attributes = _gsecret_util_attributes_for_varargs (schema, va); + va_end (va); + + value = gsecret_service_lookup_passwordv_sync (self, attributes, cancellable, error); + + g_hash_table_unref (attributes); + + return value; } -#endif +GSecretValue * +gsecret_service_lookup_passwordv_sync (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GError **error) +{ + SyncClosure *closure; + GSecretValue *value; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (attributes != NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + + closure = sync_closure_new (); + g_main_context_push_thread_default (closure->context); + + gsecret_service_lookup_passwordv (self, attributes, cancellable, + on_sync_result, closure); + + g_main_loop_run (closure->loop); + + value = gsecret_service_lookup_password_finish (self, closure->result, error); + + g_main_context_pop_thread_default (closure->context); + sync_closure_free (closure); + + return value; +} typedef struct { GCancellable *cancellable; diff --git a/library/gsecret-service.h b/library/gsecret-service.h index a65a621..bb1050b 100644 --- a/library/gsecret-service.h +++ b/library/gsecret-service.h @@ -235,30 +235,48 @@ gboolean gsecret_service_prompt_finish (GSecretService *se GAsyncResult *result, GError **error); -#if 0 void gsecret_service_store_password (GSecretService *self, const GSecretSchema *schema, const gchar *collection_path, const gchar *label, - const gchar *password, + GSecretValue *value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, ...) G_GNUC_NULL_TERMINATED; +void gsecret_service_store_passwordv (GSecretService *self, + const GSecretSchema *schema, + GHashTable *attributes, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean gsecret_service_store_password_finish (GSecretService *self, GAsyncResult *result, GError **error); -void gsecret_service_store_password_sync (GSecretService *self, +gboolean gsecret_service_store_password_sync (GSecretService *self, const GSecretSchema *schema, - const gchar *collection, - const gchar *display_name, - const gchar *password, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; +gboolean gsecret_service_store_passwordv_sync (GSecretService *self, + const GSecretSchema *schema, + GHashTable *attributes, + const gchar *collection_path, + const gchar *label, + GSecretValue *value, + GCancellable *cancellable, + GError **error); + void gsecret_service_lookup_password (GSecretService *self, const GSecretSchema *schema, GCancellable *cancellable, @@ -266,16 +284,26 @@ void gsecret_service_lookup_password (GSecretService *se gpointer user_data, ...) G_GNUC_NULL_TERMINATED; -gchar * gsecret_service_lookup_password_finish (GSecretService *self, +void gsecret_service_lookup_passwordv (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GSecretValue * gsecret_service_lookup_password_finish (GSecretService *self, GAsyncResult *result, GError **error); -gchar * gsecret_service_lookup_password_sync (GSecretService *self, +GSecretValue * gsecret_service_lookup_password_sync (GSecretService *self, const GSecretSchema *schema, GCancellable *cancellable, GError **error, ...) G_GNUC_NULL_TERMINATED; -#endif + +GSecretValue * gsecret_service_lookup_passwordv_sync (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GError **error); void gsecret_service_delete_path (GSecretService *self, const gchar *item_path, diff --git a/library/gsecret-util.c b/library/gsecret-util.c index 45c97f1..7c2b5f7 100644 --- a/library/gsecret-util.c +++ b/library/gsecret-util.c @@ -99,6 +99,23 @@ _gsecret_util_variant_for_attributes (GHashTable *attributes) } +GHashTable * +_gsecret_util_attributes_for_variant (GVariant *variant) +{ + GVariantIter iter; + GHashTable *attributes; + gchar *value; + gchar *key; + + attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_next (&iter, "{sv}", &key, &value)) + g_hash_table_insert (attributes, key, value); + + return attributes; +} + GHashTable * _gsecret_util_attributes_for_varargs (const GSecretSchema *schema, va_list args) @@ -166,3 +183,105 @@ _gsecret_util_attributes_for_varargs (const GSecretSchema *schema, return attributes; } + +static void +on_set_property (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; + GVariant *retval; + + retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), + result, &error); + if (error != NULL) + g_simple_async_result_take_error (res, error); + if (retval != NULL) + g_variant_unref (retval); + g_simple_async_result_set_op_res_gboolean (res, retval != NULL); + g_object_unref (res); +} + +void +_gsecret_util_set_property (GDBusProxy *proxy, + const gchar *property, + GVariant *value, + gpointer result_tag, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (proxy), callback, user_data, result_tag); + + g_dbus_connection_call (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + GSECRET_PROPERTIES_INTERFACE, + "Set", + g_variant_new ("(ssv)", + g_dbus_proxy_get_interface_name (proxy), + property, + value), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, on_set_property, + g_object_ref (res)); + + g_object_unref (res); +} + +gboolean +_gsecret_util_set_property_finish (GDBusProxy *proxy, + gpointer result_tag, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), result_tag), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + res = G_SIMPLE_ASYNC_RESULT (result); + + if (g_simple_async_result_propagate_error (res, error)) + return FALSE; + + return g_simple_async_result_get_op_res_gboolean (res); +} + + +gboolean +_gsecret_util_set_property_sync (GDBusProxy *proxy, + const gchar *property, + GVariant *value, + GCancellable *cancellable, + GError **error) +{ + GVariant *retval; + + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + retval = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy), + g_dbus_proxy_get_name (proxy), + g_dbus_proxy_get_object_path (proxy), + GSECRET_PROPERTIES_INTERFACE, + "Set", + g_variant_new ("(ssv)", + g_dbus_proxy_get_interface_name (proxy), + property, + value), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, error); + + if (retval != NULL) + g_variant_unref (retval); + + return (retval != NULL); +} diff --git a/library/gsecret-value.c b/library/gsecret-value.c index 6980264..97d6819 100644 --- a/library/gsecret-value.c +++ b/library/gsecret-value.c @@ -12,6 +12,7 @@ #include "config.h" +#include "gsecret-private.h" #include "gsecret-value.h" #include "egg/egg-secure-memory.h" @@ -112,7 +113,7 @@ gsecret_value_unref (gpointer value) { GSecretValue *val = value; - g_return_if_fail (value); + g_return_if_fail (value != NULL); if (g_atomic_int_dec_and_test (&val->refs)) { g_free (val->content_type); @@ -121,3 +122,35 @@ gsecret_value_unref (gpointer value) g_slice_free (GSecretValue, val); } } + +gchar * +_gsecret_value_unref_to_password (GSecretValue *value) +{ + GSecretValue *val = value; + gchar *result; + + g_return_val_if_fail (value != NULL, NULL); + + if (val->content_type && !g_str_equal (val->content_type, "text/plain")) { + gsecret_value_unref (value); + return NULL; + } + + if (g_atomic_int_dec_and_test (&val->refs)) { + if (val->destroy == egg_secure_free) { + result = val->secret; + + } else { + result = egg_secure_strdup (val->secret); + if (val->destroy) + (val->destroy) (val->secret); + } + g_free (val->content_type); + g_slice_free (GSecretValue, val); + + } else { + result = egg_secure_strdup (val->secret); + } + + return result; +} diff --git a/library/gsecret-value.h b/library/gsecret-value.h index 2046467..556827e 100644 --- a/library/gsecret-value.h +++ b/library/gsecret-value.h @@ -21,13 +21,13 @@ G_BEGIN_DECLS #define GSECRET_TYPE_VALUE (gsecret_service_get_type ()) -GType gsecret_value_get_type (void) G_GNUC_CONST; +GType gsecret_value_get_type (void) G_GNUC_CONST; -GSecretValue* gsecret_value_new (const gchar *secret, +GSecretValue* gsecret_value_new (const gchar *secret, gssize length, const gchar *content_type); -GSecretValue* gsecret_value_new_full (gchar *secret, +GSecretValue* gsecret_value_new_full (gchar *secret, gssize length, const gchar *content_type, GDestroyNotify destroy); diff --git a/library/tests/test-prompt.c b/library/tests/test-prompt.c index c7197cb..620da2b 100644 --- a/library/tests/test-prompt.c +++ b/library/tests/test-prompt.c @@ -265,16 +265,15 @@ test_prompt_result (Test *test, prompt = gsecret_prompt_instance (test->service, "/org/freedesktop/secrets/prompts/result"); - result = gsecret_prompt_get_result_value (prompt); + result = gsecret_prompt_get_result_value (prompt, NULL); g_assert (result == NULL); ret = gsecret_prompt_perform_sync (prompt, 0, NULL, &error); g_assert_no_error (error); g_assert (ret == TRUE); - result = gsecret_prompt_get_result_value (prompt); + result = gsecret_prompt_get_result_value (prompt, G_VARIANT_TYPE_STRING); g_assert (result != NULL); - g_assert_cmpstr (g_variant_get_type_string (result), ==, "s"); g_assert_cmpstr (g_variant_get_string (result, NULL), ==, "Special Result"); g_variant_unref (result); @@ -297,9 +296,8 @@ test_prompt_window_id (Test *test, g_assert_no_error (error); g_assert (ret == TRUE); - result = gsecret_prompt_get_result_value (prompt); + result = gsecret_prompt_get_result_value (prompt, G_VARIANT_TYPE_STRING); g_assert (result != NULL); - g_assert_cmpstr (g_variant_get_type_string (result), ==, "s"); g_assert_cmpstr (g_variant_get_string (result, NULL), ==, "555"); g_variant_unref (result);