Tests for GSecretItem and GSecretValue

* And fix bugs found in the process
This commit is contained in:
Stef Walter 2012-01-23 17:20:18 +01:00
parent 116447c59e
commit f44aae6efa
16 changed files with 2284 additions and 834 deletions

View File

@ -20,6 +20,7 @@ libgsecret_la_SOURCES = \
gsecret-password.h gsecret-password.c \
gsecret-prompt.h gsecret-prompt.c \
gsecret-service.h gsecret-service.c \
gsecret-session.h gsecret-session.c \
gsecret-util.c \
gsecret-value.h gsecret-value.c \
$(BUILT_SOURCES) \

View File

@ -1,6 +1,6 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Red Hat Inc.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@ -23,6 +23,7 @@
enum {
PROP_0,
PROP_SERVICE,
PROP_ITEMS,
PROP_LABEL,
PROP_LOCKED,
@ -34,6 +35,7 @@ struct _GSecretCollectionPrivate {
/* Doesn't change between construct and finalize */
GSecretService *service;
GCancellable *cancellable;
gboolean constructing;
/* Protected by mutex */
GMutex mutex;
@ -58,6 +60,7 @@ gsecret_collection_init (GSecretCollection *self)
g_mutex_init (&self->pv->mutex);
self->pv->cancellable = g_cancellable_new ();
self->pv->items = items_table_new ();
self->pv->constructing = TRUE;
}
static void
@ -86,6 +89,13 @@ gsecret_collection_set_property (GObject *obj,
GSecretCollection *self = GSECRET_COLLECTION (obj);
switch (prop_id) {
case PROP_SERVICE:
g_return_if_fail (self->pv->service == NULL);
self->pv->service = g_value_get_object (value);
if (self->pv->service)
g_object_add_weak_pointer (G_OBJECT (self->pv->service),
(gpointer *)&self->pv->service);
break;
case PROP_LABEL:
gsecret_collection_set_label (self, g_value_get_string (value),
self->pv->cancellable, on_set_label,
@ -106,6 +116,9 @@ gsecret_collection_get_property (GObject *obj,
GSecretCollection *self = GSECRET_COLLECTION (obj);
switch (prop_id) {
case PROP_SERVICE:
g_value_set_object (value, self->pv->service);
break;
case PROP_ITEMS:
g_value_take_boxed (value, gsecret_collection_get_items (self));
break;
@ -132,10 +145,9 @@ gsecret_collection_dispose (GObject *obj)
{
GSecretCollection *self = GSECRET_COLLECTION (obj);
g_clear_object (&self->pv->service);
g_cancellable_cancel (self->pv->cancellable);
G_OBJECT_GET_CLASS (obj)->dispose (obj);
G_OBJECT_CLASS (gsecret_collection_parent_class)->dispose (obj);
}
static void
@ -143,14 +155,19 @@ gsecret_collection_finalize (GObject *obj)
{
GSecretCollection *self = GSECRET_COLLECTION (obj);
if (self->pv->service)
g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
(gpointer *)&self->pv->service);
g_mutex_clear (&self->pv->mutex);
g_hash_table_destroy (self->pv->items);
g_object_unref (self->pv->cancellable);
G_OBJECT_GET_CLASS (obj)->finalize (obj);
G_OBJECT_CLASS (gsecret_collection_parent_class)->finalize (obj);
}
typedef struct {
GSecretCollection *collection;
GCancellable *cancellable;
GHashTable *items;
gint items_loading;
@ -160,6 +177,7 @@ static void
load_closure_free (gpointer data)
{
LoadClosure *closure = data;
g_object_unref (closure->collection);
g_clear_object (&closure->cancellable);
g_hash_table_unref (closure->items);
g_slice_free (LoadClosure, closure);
@ -174,7 +192,7 @@ load_result_new (GCancellable *cancellable,
LoadClosure *closure;
res = g_simple_async_result_new (NULL, callback, user_data, load_result_new);
closure = g_slice_new (LoadClosure);
closure = g_slice_new0 (LoadClosure);
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
closure->items = items_table_new ();
g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
@ -183,10 +201,10 @@ load_result_new (GCancellable *cancellable,
}
static void
load_items_complete (GSecretCollection *self,
GSimpleAsyncResult *res)
load_items_complete (GSimpleAsyncResult *res)
{
LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretCollection *self = closure->collection;
GHashTable *items;
g_assert (closure->items_loading == 0);
@ -209,7 +227,6 @@ on_item_loading (GObject *source,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GSecretCollection *self = GSECRET_COLLECTION (g_async_result_get_source_object (user_data));
LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
const gchar *item_path;
GError *error = NULL;
@ -223,14 +240,13 @@ on_item_loading (GObject *source,
g_simple_async_result_take_error (res, error);
if (item != NULL) {
item_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
item_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (item));
g_hash_table_insert (closure->items, g_strdup (item_path), item);
}
if (closure->items_loading == 0)
load_items_complete (self, res);
load_items_complete (res);
g_object_unref (self);
g_object_unref (res);
}
@ -244,16 +260,23 @@ load_items_perform (GSecretCollection *self,
GVariantIter iter;
gchar *item_path;
g_assert (GSECRET_IS_COLLECTION (self));
g_assert (item_paths != NULL);
g_assert (closure->collection == NULL);
closure->collection = g_object_ref (self);
g_variant_iter_init (&iter, item_paths);
while (g_variant_iter_loop (&iter, "o", &item_path)) {
g_mutex_lock (&self->pv->mutex);
item = g_hash_table_lookup (self->pv->items, item_path);
if (item == NULL)
if (item != NULL)
g_object_ref (item);
g_mutex_unlock (&self->pv->mutex);
if (item == NULL) {
// TODO: xxxxxxxxxxxx;
gsecret_item_new (self->pv->service, item_path,
closure->cancellable, on_item_loading,
g_object_ref (res));
@ -267,9 +290,7 @@ load_items_perform (GSecretCollection *self,
}
if (closure->items_loading == 0)
load_items_complete (self, res);
g_variant_unref (item_paths);
load_items_complete (res);
}
static void
@ -291,7 +312,7 @@ handle_property_changed (GSecretCollection *self,
else if (g_str_equal (property_name, "Modified"))
g_object_notify (G_OBJECT (self), "modified");
else if (g_str_equal (property_name, "Items")) {
else if (g_str_equal (property_name, "Items") && !self->pv->constructing) {
res = load_result_new (self->pv->cancellable, NULL, NULL);
if (value == NULL)
@ -302,6 +323,7 @@ handle_property_changed (GSecretCollection *self,
g_warning ("couldn't retrieve Collection Items property");
g_simple_async_result_complete (res);
} else {
// TODO: yyyy;
load_items_perform (self, res, value);
g_variant_unref (value);
}
@ -324,6 +346,7 @@ gsecret_collection_properties_changed (GDBusProxy *proxy,
g_variant_iter_init (&iter, changed_properties);
while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
// TODO: zzzz;
handle_property_changed (self, property_name, value);
g_object_thaw_notify (G_OBJECT (self));
@ -342,25 +365,31 @@ gsecret_collection_class_init (GSecretCollectionClass *klass)
proxy_class->g_properties_changed = gsecret_collection_properties_changed;
g_object_class_install_property (gobject_class, PROP_SERVICE,
g_param_spec_object ("service", "Service", "Secret Service",
GSECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ITEMS,
g_param_spec_boxed ("items", "Items", "Items in collection",
_gsecret_list_get_type (), G_PARAM_READABLE));
_gsecret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LABEL,
g_param_spec_string ("label", "Label", "Item label",
NULL, G_PARAM_READWRITE));
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LOCKED,
g_param_spec_boolean ("locked", "Locked", "Item locked",
TRUE, G_PARAM_READABLE));
TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CREATED,
g_param_spec_uint64 ("created", "Created", "Item creation date",
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE));
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MODIFIED,
g_param_spec_uint64 ("modified", "Modified", "Item modified date",
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE));
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_type_class_add_private (gobject_class, sizeof (GSecretCollectionPrivate));
}
static void
@ -369,24 +398,40 @@ on_collection_new (GObject *source,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GSecretCollection *self;
GObject *source_object;
GError *error = NULL;
GVariant *item_paths;
GObject *object;
GDBusProxy *proxy;
source_object = g_async_result_get_source_object (user_data);
source_object = g_async_result_get_source_object (result);
object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
result, &error);
g_object_unref (source_object);
proxy = G_DBUS_PROXY (object);
if (error == NULL && !_gsecret_util_have_cached_properties (proxy)) {
g_set_error (&error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
"No such secret collection at path: %s", g_dbus_proxy_get_object_path (proxy));
}
if (error == NULL) {
load_items_perform (GSECRET_COLLECTION (object), res, NULL);
g_simple_async_result_set_op_res_gpointer (res, object, g_object_unref);
self = GSECRET_COLLECTION (object);
self->pv->constructing = FALSE;
item_paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (object), "Items");
g_return_if_fail (item_paths != NULL);
// TODO: yyyy;
load_items_perform (self, res, item_paths);
g_variant_unref (item_paths);
} else {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
g_clear_object (&object);
g_object_unref (res);
}
@ -410,6 +455,7 @@ gsecret_collection_new (GSecretService *service,
g_async_initable_new_async (GSECRET_SERVICE_GET_CLASS (service)->collection_gtype,
G_PRIORITY_DEFAULT,
cancellable,
// TODO: zzzz;
on_collection_new,
g_object_ref (res),
"g-flags", G_DBUS_CALL_FLAGS_NONE,
@ -418,6 +464,7 @@ gsecret_collection_new (GSecretService *service,
"g-connection", g_dbus_proxy_get_connection (proxy),
"g-object-path", collection_path,
"g-interface-name", GSECRET_COLLECTION_INTERFACE,
"service", service,
NULL);
g_object_unref (res);
@ -427,18 +474,19 @@ GSecretCollection *
gsecret_collection_new_finish (GAsyncResult *result,
GError **error)
{
GObject *object;
GObject *source_object;
GSimpleAsyncResult *res;
LoadClosure *closure;
source_object = g_async_result_get_source_object (result);
object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
result, error);
g_object_unref (source_object);
g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, load_result_new), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (object != NULL)
return GSECRET_COLLECTION (object);
else
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);
return g_object_ref (closure->collection);
}
GSecretCollection *
@ -458,6 +506,7 @@ gsecret_collection_new_sync (GSecretService *service,
sync = _gsecret_sync_new ();
g_main_context_push_thread_default (sync->context);
// TODO: xxxxx;
gsecret_collection_new (service, collection_path, cancellable,
_gsecret_sync_on_result, sync);
@ -590,7 +639,7 @@ gsecret_collection_set_label (GSecretCollection *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (GSECRET_IS_ITEM (self));
g_return_if_fail (GSECRET_IS_COLLECTION (self));
g_return_if_fail (label != NULL);
_gsecret_util_set_property (G_DBUS_PROXY (self), "Label",
@ -604,7 +653,7 @@ gsecret_collection_set_label_finish (GSecretCollection *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE);
g_return_val_if_fail (GSECRET_IS_COLLECTION (self), FALSE);
return _gsecret_util_set_property_finish (G_DBUS_PROXY (self),
gsecret_collection_set_label,
@ -617,7 +666,7 @@ gsecret_collection_set_label_sync (GSecretCollection *self,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE);
g_return_val_if_fail (GSECRET_IS_COLLECTION (self), FALSE);
g_return_val_if_fail (label != NULL, FALSE);
return _gsecret_util_set_property_sync (G_DBUS_PROXY (self), "Label",

View File

@ -1,6 +1,6 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published

View File

@ -1,6 +1,6 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@ -23,6 +23,7 @@
enum {
PROP_0,
PROP_SERVICE,
PROP_ATTRIBUTES,
PROP_LABEL,
PROP_LOCKED,
@ -38,17 +39,11 @@ typedef struct _GSecretItemPrivate {
G_DEFINE_TYPE (GSecretItem, gsecret_item, G_TYPE_DBUS_PROXY);
static GSecretItemPrivate *
gsecret_item_private_get (GSecretItem *self)
{
return G_TYPE_INSTANCE_GET_PRIVATE (self, GSECRET_TYPE_ITEM, GSecretItemPrivate);
}
static void
gsecret_item_init (GSecretItem *self)
{
GSecretItemPrivate *pv = gsecret_item_private_get (self);
pv->cancellable = g_cancellable_new ();
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSECRET_TYPE_ITEM, GSecretItemPrivate);
self->pv->cancellable = g_cancellable_new ();
}
static void
@ -92,17 +87,23 @@ gsecret_item_set_property (GObject *obj,
GParamSpec *pspec)
{
GSecretItem *self = GSECRET_ITEM (obj);
GSecretItemPrivate *pv = gsecret_item_private_get (self);
switch (prop_id) {
case PROP_SERVICE:
g_return_if_fail (self->pv->service == NULL);
self->pv->service = g_value_get_object (value);
if (self->pv->service)
g_object_add_weak_pointer (G_OBJECT (self->pv->service),
(gpointer *)&self->pv->service);
break;
case PROP_ATTRIBUTES:
gsecret_item_set_attributes (self, g_value_get_boxed (value),
pv->cancellable, on_set_attributes,
self->pv->cancellable, on_set_attributes,
g_object_ref (self));
break;
case PROP_LABEL:
gsecret_item_set_label (self, g_value_get_string (value),
pv->cancellable, on_set_label,
self->pv->cancellable, on_set_label,
g_object_ref (self));
break;
default:
@ -120,6 +121,9 @@ gsecret_item_get_property (GObject *obj,
GSecretItem *self = GSECRET_ITEM (obj);
switch (prop_id) {
case PROP_SERVICE:
g_value_set_object (value, self->pv->service);
break;
case PROP_ATTRIBUTES:
g_value_take_boxed (value, gsecret_item_get_attributes (self));
break;
@ -145,23 +149,24 @@ static void
gsecret_item_dispose (GObject *obj)
{
GSecretItem *self = GSECRET_ITEM (obj);
GSecretItemPrivate *pv = gsecret_item_private_get (self);
g_clear_object (&pv->service);
g_cancellable_cancel (pv->cancellable);
g_cancellable_cancel (self->pv->cancellable);
G_OBJECT_GET_CLASS (obj)->dispose (obj);
G_OBJECT_CLASS (gsecret_item_parent_class)->dispose (obj);
}
static void
gsecret_item_finalize (GObject *obj)
{
GSecretItem *self = GSECRET_ITEM (obj);
GSecretItemPrivate *pv = gsecret_item_private_get (self);
g_clear_object (&pv->cancellable);
if (self->pv->service)
g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
(gpointer *)&self->pv->service);
G_OBJECT_GET_CLASS (obj)->finalize (obj);
g_object_unref (self->pv->cancellable);
G_OBJECT_CLASS (gsecret_item_parent_class)->finalize (obj);
}
static void
@ -216,27 +221,48 @@ gsecret_item_class_init (GSecretItemClass *klass)
proxy_class->g_properties_changed = gsecret_item_properties_changed;
g_object_class_install_property (gobject_class, PROP_SERVICE,
g_param_spec_object ("service", "Service", "Secret Service",
GSECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ATTRIBUTES,
g_param_spec_boxed ("attributes", "Attributes", "Item attributes",
G_TYPE_HASH_TABLE, G_PARAM_READWRITE));
G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LABEL,
g_param_spec_string ("label", "Label", "Item label",
NULL, G_PARAM_READWRITE));
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LOCKED,
g_param_spec_boolean ("locked", "Locked", "Item locked",
TRUE, G_PARAM_READABLE));
TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_CREATED,
g_param_spec_uint64 ("created", "Created", "Item creation date",
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE));
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_MODIFIED,
g_param_spec_uint64 ("modified", "Modified", "Item modified date",
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE));
0UL, G_MAXUINT64, 0UL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_type_class_add_private (gobject_class, sizeof (GSecretItemPrivate));
}
#if 0
static void
all_properties_changed (GSecretItem *item)
{
GObject *obj = G_OBJECT (item);
gchar **property_names;
guint i;
property_names = g_dbus_proxy_get_cached_property_names (G_DBUS_PROXY (item));
for (i = 0; property_names != NULL && property_names[i] != NULL; i++)
handle_property_changed (obj, property_names[i]);
g_strfreev (property_names);
}
#endif
void
gsecret_item_new (GSecretService *service,
const gchar *item_path,
@ -263,6 +289,7 @@ gsecret_item_new (GSecretService *service,
"g-connection", g_dbus_proxy_get_connection (proxy),
"g-object-path", item_path,
"g-interface-name", GSECRET_ITEM_INTERFACE,
"service", service,
NULL);
}
@ -272,16 +299,25 @@ gsecret_item_new_finish (GAsyncResult *result,
{
GObject *object;
GObject *source_object;
GDBusProxy *proxy;
source_object = g_async_result_get_source_object (result);
object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
result, error);
g_object_unref (source_object);
if (object != NULL)
return GSECRET_ITEM (object);
else
if (object == NULL)
return NULL;
proxy = G_DBUS_PROXY (object);
if (!_gsecret_util_have_cached_properties (proxy)) {
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
"No such secret item at path: %s", g_dbus_proxy_get_object_path (proxy));
g_object_unref (object);
return NULL;
}
return GSECRET_ITEM (object);
}
GSecretItem *
@ -290,30 +326,29 @@ gsecret_item_new_sync (GSecretService *service,
GCancellable *cancellable,
GError **error)
{
GInitable *initable;
GDBusProxy *proxy;
proxy = G_DBUS_PROXY (service);
GSecretSync *sync;
GSecretItem *item;
g_return_val_if_fail (GSECRET_IS_SERVICE (service), NULL);
g_return_val_if_fail (item_path != NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
initable = g_initable_new (GSECRET_TYPE_ITEM,
cancellable,
error,
"g-flags", G_DBUS_CALL_FLAGS_NONE,
"g-interface-info", _gsecret_gen_item_interface_info (),
"g-name", g_dbus_proxy_get_name (proxy),
"g-connection", g_dbus_proxy_get_connection (proxy),
"g-object-path", item_path,
"g-interface-name", GSECRET_ITEM_INTERFACE,
NULL);
sync = _gsecret_sync_new ();
g_main_context_push_thread_default (sync->context);
if (initable != NULL)
return GSECRET_ITEM (initable);
else
return NULL;
// TODO: xxxxx;
gsecret_item_new (service, item_path, cancellable,
_gsecret_sync_on_result, sync);
g_main_loop_run (sync->loop);
item = gsecret_item_new_finish (sync->result, error);
g_main_context_pop_thread_default (sync->context);
_gsecret_sync_free (sync);
return item;
}
void
@ -335,8 +370,10 @@ on_item_deleted (GObject *source,
GSecretItem *self = GSECRET_ITEM (g_async_result_get_source_object (user_data));
GError *error = NULL;
if (gsecret_service_delete_path_finish (GSECRET_SERVICE (source), result, &error))
if (gsecret_service_delete_path_finish (GSECRET_SERVICE (source), result, &error)) {
g_simple_async_result_set_op_res_gboolean (res, TRUE);
g_object_run_dispose (G_OBJECT (self));
}
if (error != NULL)
g_simple_async_result_take_error (res, error);
@ -352,19 +389,17 @@ gsecret_item_delete (GSecretItem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSecretItemPrivate *pv;
GSimpleAsyncResult *res;
const gchar *object_path;
g_return_if_fail (GSECRET_IS_ITEM (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
pv = gsecret_item_private_get (self);
object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
gsecret_item_delete);
gsecret_service_delete_path (pv->service, object_path, cancellable,
gsecret_service_delete_path (self->pv->service, object_path, cancellable,
on_item_deleted, g_object_ref (res));
g_object_unref (res);
@ -375,13 +410,19 @@ gsecret_item_delete_finish (GSecretItem *self,
GAsyncResult *result,
GError **error)
{
GSecretItemPrivate *pv;
GSimpleAsyncResult *res;
g_return_val_if_fail (GSECRET_IS_ITEM (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_item_delete), FALSE);
pv = gsecret_item_private_get (self);
return gsecret_service_delete_path_finish (pv->service, result, error);
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
@ -411,31 +452,47 @@ gsecret_item_delete_sync (GSecretItem *self,
return ret;
}
typedef struct {
GCancellable *cancellable;
GSecretValue *value;
} GetClosure;
static void
get_closure_free (gpointer data)
{
GetClosure *closure = data;
g_clear_object (&closure->cancellable);
gsecret_value_unref (closure->value);
g_slice_free (GetClosure, closure);
}
static void
on_item_get_secret_ready (GObject *source, GAsyncResult *result, gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GSecretItem *self = GSECRET_ITEM (g_async_result_get_source_object (user_data));
GSecretItemPrivate *pv = gsecret_item_private_get (self);
GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretSession *session;
GError *error = NULL;
GSecretValue *value;
GVariant *ret;
GVariant *retval;
GVariant *child;
ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
if (error == NULL) {
value = _gsecret_service_decode_secret (pv->service, ret);
if (value == NULL) {
child = g_variant_get_child_value (retval, 0);
g_variant_unref (retval);
session = _gsecret_service_get_session (self->pv->service);
closure->value = _gsecret_session_decode_secret (session, child);
g_variant_unref (child);
if (closure->value == NULL)
g_set_error (&error, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL,
_("Received invalid secret from the secret storage"));
}
g_object_unref (ret);
}
if (error != NULL)
g_simple_async_result_take_error (res, error);
else
g_simple_async_result_set_op_res_gpointer (res, value,
gsecret_value_unref);
g_simple_async_result_complete (res);
g_object_unref (res);
@ -446,13 +503,11 @@ on_service_ensure_session (GObject *source, GAsyncResult *result, gpointer user_
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
GSecretItem *self = GSECRET_ITEM (g_async_result_get_source_object (user_data));
GSecretItemPrivate *pv = gsecret_item_private_get (self);
GError *error = NULL;
GCancellable *cancellable = NULL;
GetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
const gchar *session_path;
GError *error = NULL;
session_path = _gsecret_service_ensure_session_finish (pv->service, result,
&cancellable, &error);
session_path = gsecret_service_ensure_session_finish (self->pv->service, result, &error);
if (error != NULL) {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
@ -460,31 +515,33 @@ on_service_ensure_session (GObject *source, GAsyncResult *result, gpointer user_
} else {
g_assert (session_path != NULL && session_path[0] != '\0');
g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret",
g_variant_new ("o", session_path),
G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
g_variant_new ("(o)", session_path),
G_DBUS_CALL_FLAGS_NONE, -1, closure->cancellable,
on_item_get_secret_ready, g_object_ref (res));
}
g_clear_object (&cancellable);
g_object_unref (res);
}
void
gsecret_item_get_secret (GSecretItem *self, GCancellable *cancellable,
GAsyncReadyCallback callback, gpointer user_data)
gsecret_item_get_secret (GSecretItem *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
GSecretItemPrivate *pv;
GetClosure *closure;
g_return_if_fail (GSECRET_IS_ITEM (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = g_simple_async_result_new (G_OBJECT (self), callback,
user_data, gsecret_item_get_secret);
closure = g_slice_new0 (GetClosure);
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
g_simple_async_result_set_op_res_gpointer (res, closure, get_closure_free);
pv = gsecret_item_private_get (self);
gsecret_service_ensure_session (pv->service, cancellable,
gsecret_service_ensure_session (self->pv->service, cancellable,
on_service_ensure_session,
g_object_ref (res));
@ -492,10 +549,12 @@ gsecret_item_get_secret (GSecretItem *self, GCancellable *cancellable,
}
GSecretValue*
gsecret_item_get_secret_finish (GSecretItem *self, GAsyncResult *result,
gsecret_item_get_secret_finish (GSecretItem *self,
GAsyncResult *result,
GError **error)
{
GSimpleAsyncResult *res;
GetClosure *closure;
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
gsecret_item_get_secret), NULL);
@ -504,7 +563,8 @@ gsecret_item_get_secret_finish (GSecretItem *self, GAsyncResult *result,
if (g_simple_async_result_propagate_error (res, error))
return NULL;
return gsecret_value_ref (g_simple_async_result_get_op_res_gpointer (res));
closure = g_simple_async_result_get_op_res_gpointer (res);
return closure->value ? gsecret_value_ref (closure->value) : NULL;
}
GSecretValue*
@ -558,18 +618,13 @@ gsecret_item_set_attributes (GSecretItem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
GVariant *variant;
g_return_if_fail (GSECRET_IS_ITEM (self));
g_return_if_fail (attributes != NULL);
variant = _gsecret_util_variant_for_attributes (attributes);
_gsecret_util_set_property (G_DBUS_PROXY (self), "Attributes", variant,
_gsecret_util_set_property (G_DBUS_PROXY (self), "Attributes",
_gsecret_util_variant_for_attributes (attributes),
gsecret_item_set_attributes, cancellable,
callback, user_data);
g_variant_unref (variant);
}
gboolean
@ -590,20 +645,12 @@ gsecret_item_set_attributes_sync (GSecretItem *self,
GCancellable *cancellable,
GError **error)
{
GVariant *variant;
gboolean ret;
g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE);
g_return_val_if_fail (attributes != NULL, FALSE);
variant = _gsecret_util_variant_for_attributes (attributes);
ret = _gsecret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes",
variant, cancellable, error);
g_variant_unref (variant);
return ret;
return _gsecret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes",
_gsecret_util_variant_for_attributes (attributes),
cancellable, error);
}
gchar *

View File

@ -1,6 +1,6 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@ -29,10 +29,11 @@ G_BEGIN_DECLS
#define GSECRET_ITEM_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_ITEM, GSecretItemClass))
typedef struct _GSecretItemClass GSecretItemClass;
typedef struct _GSecretItemPrivate GSecretItemPrivate;
struct _GSecretItem {
GDBusProxy parent_instance;
gpointer padding;
GSecretItemPrivate *pv;;
};
struct _GSecretItemClass {

View File

@ -26,6 +26,8 @@ typedef struct {
GMainLoop *loop;
} GSecretSync;
typedef struct _GSecretSession GSecretSession;
#define GSECRET_SERVICE_PATH "/org/freedesktop/secrets"
#define GSECRET_SERVICE_BUS_NAME "org.freedesktop.Secret.Service"
@ -93,6 +95,8 @@ gboolean _gsecret_util_set_property_sync (GDBusProxy *prox
GCancellable *cancellable,
GError **error);
gboolean _gsecret_util_have_cached_properties (GDBusProxy *proxy);
void _gsecret_service_set_default_bus_name (const gchar *bus_name);
GSecretService * _gsecret_service_bare_instance (GDBusConnection *connection,
@ -107,16 +111,10 @@ void _gsecret_service_bare_connect (const gchar *bus
GSecretService * _gsecret_service_bare_connect_finish (GAsyncResult *result,
GError **error);
GVariant * _gsecret_service_encode_secret (GSecretService *self,
GSecretValue *value);
GSecretSession * _gsecret_service_get_session (GSecretService *self);
GSecretValue * _gsecret_service_decode_secret (GSecretService *service,
GVariant *encoded);
const gchar * _gsecret_service_ensure_session_finish (GSecretService *self,
GAsyncResult *result,
GCancellable **cancellable,
GError **error);
void _gsecret_service_take_session (GSecretService *self,
GSecretSession *session);
GSecretItem * _gsecret_service_find_item_instance (GSecretService *self,
const gchar *item_path);
@ -126,6 +124,26 @@ GSecretItem * _gsecret_collection_find_item_instance (GSecretCollectio
gchar * _gsecret_value_unref_to_password (GSecretValue *value);
void _gsecret_session_free (gpointer data);
const gchar * _gsecret_session_get_algorithms (GSecretSession *session);
const gchar * _gsecret_session_get_path (GSecretSession *session);
void _gsecret_session_open (GSecretService *service,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GSecretSession * _gsecret_session_open_finish (GAsyncResult *result,
GError **error);
GVariant * _gsecret_session_encode_secret (GSecretSession *session,
GSecretValue *value);
GSecretValue * _gsecret_session_decode_secret (GSecretSession *session,
GVariant *encoded);
G_END_DECLS
#endif /* __G_SERVICE_H___ */

View File

@ -1,6 +1,7 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@ -20,13 +21,6 @@
#include "gsecret-types.h"
#include "gsecret-value.h"
#ifdef WITH_GCRYPT
#include "egg/egg-dh.h"
#include "egg/egg-hkdf.h"
#include "egg/egg-libgcrypt.h"
#endif
#include "egg/egg-hex.h"
#include "egg/egg-secure-memory.h"
#include <glib.h>
@ -40,21 +34,6 @@ EGG_SECURE_DECLARE (secret_service);
static const gchar *default_bus_name = GSECRET_SERVICE_BUS_NAME;
#define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7"
#define ALGORITHMS_PLAIN "plain"
typedef struct {
gchar *path;
const gchar *algorithms;
#ifdef WITH_GCRYPT
gcry_mpi_t prime;
gcry_mpi_t privat;
gcry_mpi_t publi;
#endif
gpointer key;
gsize n_key;
} GSecretSession;
enum {
PROP_0,
PROP_COLLECTIONS
@ -75,24 +54,6 @@ static gpointer service_instance = NULL;
G_DEFINE_TYPE (GSecretService, gsecret_service, G_TYPE_DBUS_PROXY);
static void
gsecret_session_free (gpointer data)
{
GSecretSession *session = data;
if (session == NULL)
return;
g_free (session->path);
#ifdef WITH_GCRYPT
gcry_mpi_release (session->publi);
gcry_mpi_release (session->privat);
gcry_mpi_release (session->prime);
#endif
egg_secure_free (session->key);
g_free (session);
}
static GHashTable *
collections_table_new (void)
{
@ -144,7 +105,7 @@ gsecret_service_finalize (GObject *obj)
{
GSecretService *self = GSECRET_SERVICE (obj);
gsecret_session_free (self->pv->session);
_gsecret_session_free (self->pv->session);
g_hash_table_destroy (self->pv->collections);
g_clear_object (&self->pv->cancellable);
@ -315,6 +276,7 @@ load_collections_perform (GSecretService *self,
g_mutex_unlock (&self->pv->mutex);
if (collection == NULL) {
// TODO: xxxxx;
gsecret_collection_new (self, collection_path, closure->cancellable,
on_collection_loading, g_object_ref (res));
closure->collections_loading++;
@ -349,6 +311,7 @@ handle_property_changed (GSecretService *self,
g_warning ("couldn't retrieve Service Collections property");
g_simple_async_result_complete (res);
} else {
// TODO: yyyy;
load_collections_perform (self, res, value);
g_variant_unref (value);
}
@ -392,6 +355,9 @@ gsecret_service_class_init (GSecretServiceClass *klass)
klass->prompt_async = gsecret_service_real_prompt_async;
klass->prompt_finish = gsecret_service_real_prompt_finish;
klass->item_gtype = GSECRET_TYPE_ITEM;
klass->collection_gtype = GSECRET_TYPE_COLLECTION;
g_type_class_add_private (klass, sizeof (GSecretServicePrivate));
}
@ -744,6 +710,35 @@ _gsecret_service_find_item_instance (GSecretService *self,
return item;
}
GSecretSession *
_gsecret_service_get_session (GSecretService *self)
{
GSecretSession *session;
g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL);
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
g_mutex_lock (&self->pv->mutex);
return session;
}
void
_gsecret_service_take_session (GSecretService *self,
GSecretSession *session)
{
g_return_if_fail (GSECRET_IS_SERVICE (self));
g_return_if_fail (session != NULL);
g_mutex_lock (&self->pv->mutex);
if (self->pv->session == NULL)
self->pv->session = session;
else
_gsecret_session_free (session);
g_mutex_unlock (&self->pv->mutex);
}
const gchar *
gsecret_service_get_session_algorithms (GSecretService *self)
{
@ -754,7 +749,7 @@ gsecret_service_get_session_algorithms (GSecretService *self)
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
algorithms = session ? session->algorithms : NULL;
algorithms = session ? _gsecret_session_get_algorithms (session) : NULL;
g_mutex_unlock (&self->pv->mutex);
/* Session never changes once established, so can return const */
@ -771,266 +766,13 @@ gsecret_service_get_session_path (GSecretService *self)
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
path = session ? session->path : NULL;
path = session ? _gsecret_session_get_path (session) : NULL;
g_mutex_unlock (&self->pv->mutex);
/* Session never changes once established, so can return const */
return path;
}
#ifdef WITH_GCRYPT
static GVariant *
request_open_session_aes (GSecretSession *session)
{
gcry_error_t gcry;
gcry_mpi_t base;
unsigned char *buffer;
size_t n_buffer;
GVariant *argument;
g_assert (session->prime == NULL);
g_assert (session->privat == NULL);
g_assert (session->publi == NULL);
/* Initialize our local parameters and values */
if (!egg_dh_default_params ("ietf-ike-grp-modp-1536",
&session->prime, &base))
g_return_val_if_reached (NULL);
#if 0
g_printerr ("\n lib prime: ");
gcry_mpi_dump (session->prime);
g_printerr ("\n lib base: ");
gcry_mpi_dump (base);
g_printerr ("\n");
#endif
if (!egg_dh_gen_pair (session->prime, base, 0,
&session->publi, &session->privat))
g_return_val_if_reached (NULL);
gcry_mpi_release (base);
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, session->publi);
g_return_val_if_fail (gcry == 0, NULL);
argument = g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
buffer, n_buffer, TRUE,
gcry_free, buffer);
return g_variant_new ("(sv)", ALGORITHMS_AES, argument);
}
static gboolean
response_open_session_aes (GSecretSession *session,
GVariant *response)
{
gconstpointer buffer;
GVariant *argument;
const gchar *sig;
gsize n_buffer;
gcry_mpi_t peer;
gcry_error_t gcry;
gpointer ikm;
gsize n_ikm;
sig = g_variant_get_type_string (response);
g_return_val_if_fail (sig != NULL, FALSE);
if (!g_str_equal (sig, "(vo)")) {
g_warning ("invalid OpenSession() response from daemon with signature: %s", sig);
return FALSE;
}
g_assert (session->path == NULL);
g_variant_get (response, "(vo)", &argument, &session->path);
buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar));
gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL);
g_return_val_if_fail (gcry == 0, FALSE);
g_variant_unref (argument);
#if 0
g_printerr (" lib publi: ");
gcry_mpi_dump (session->publi);
g_printerr ("\n lib peer: ");
gcry_mpi_dump (peer);
g_printerr ("\n");
#endif
ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm);
gcry_mpi_release (peer);
#if 0
g_printerr (" lib ikm: %s\n", egg_hex_encode (ikm, n_ikm));
#endif
if (ikm == NULL) {
g_warning ("couldn't negotiate a valid AES session key");
g_free (session->path);
session->path = NULL;
return FALSE;
}
session->n_key = 16;
session->key = egg_secure_alloc (session->n_key);
if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0,
session->key, session->n_key))
g_return_val_if_reached (FALSE);
egg_secure_free (ikm);
session->algorithms = ALGORITHMS_AES;
return TRUE;
}
#endif /* WITH_GCRYPT */
static GVariant *
request_open_session_plain (GSecretSession *session)
{
GVariant *argument = g_variant_new_string ("");
return g_variant_new ("(sv)", "plain", argument);
}
static gboolean
response_open_session_plain (GSecretSession *session,
GVariant *response)
{
GVariant *argument;
const gchar *sig;
sig = g_variant_get_type_string (response);
g_return_val_if_fail (sig != NULL, FALSE);
if (!g_str_equal (sig, "(vo)")) {
g_warning ("invalid OpenSession() response from daemon with signature: %s",
g_variant_get_type_string (response));
return FALSE;
}
g_assert (session->path == NULL);
g_variant_get (response, "(vo)", &argument, &session->path);
g_variant_unref (argument);
g_assert (session->key == NULL);
g_assert (session->n_key == 0);
session->algorithms = ALGORITHMS_PLAIN;
return TRUE;
}
typedef struct {
GCancellable *cancellable;
GSecretSession *session;
} OpenSessionClosure;
static void
open_session_closure_free (gpointer data)
{
OpenSessionClosure *closure = data;
g_assert (closure);
g_clear_object (&closure->cancellable);
gsecret_session_free (closure->session);
g_free (closure);
}
static void
on_service_open_session_plain (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
OpenSessionClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretService *self = GSECRET_SERVICE (source);
GError *error = NULL;
GVariant *response;
response = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error);
/* A successful response, decode it */
if (response != NULL) {
if (response_open_session_plain (closure->session, response)) {
g_mutex_lock (&self->pv->mutex);
if (self->pv->session == NULL) {
self->pv->session = closure->session;
closure->session = NULL; /* Service takes ownership */
}
g_mutex_unlock (&self->pv->mutex);
} else {
g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL,
_("Couldn't communicate with the secret storage"));
}
g_simple_async_result_complete (res);
g_variant_unref (response);
} else {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
g_object_unref (res);
}
#ifdef WITH_GCRYPT
static void
on_service_open_session_aes (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
OpenSessionClosure * closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretService *self = GSECRET_SERVICE (source);
GError *error = NULL;
GVariant *response;
response = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error);
/* A successful response, decode it */
if (response != NULL) {
if (response_open_session_aes (closure->session, response)) {
g_mutex_lock (&self->pv->mutex);
if (self->pv->session == NULL) {
self->pv->session = closure->session;
closure->session = NULL; /* Service takes ownership */
}
g_mutex_unlock (&self->pv->mutex);
} else {
g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL,
_("Couldn't communicate with the secret storage"));
}
g_simple_async_result_complete (res);
g_variant_unref (response);
} else {
/* AES session not supported, request a plain session */
if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) {
g_dbus_proxy_call (G_DBUS_PROXY (source), "OpenSession",
request_open_session_plain (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
closure->cancellable, on_service_open_session_plain,
g_object_ref (res));
g_error_free (error);
/* Other errors result in a failure */
} else {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
}
g_object_unref (res);
}
#endif /* WITH_GCRYPT */
void
gsecret_service_ensure_session (GSecretService *self,
GCancellable *cancellable,
@ -1038,72 +780,24 @@ gsecret_service_ensure_session (GSecretService *self,
gpointer user_data)
{
GSimpleAsyncResult *res;
OpenSessionClosure *closure;
GSecretSession *session;
g_return_if_fail (GSECRET_IS_SERVICE (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
gsecret_service_ensure_session);
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
g_mutex_unlock (&self->pv->mutex);
/* If we have no session, then request an AES session */
if (session == NULL) {
_gsecret_session_open (self, cancellable, callback, user_data);
closure = g_new (OpenSessionClosure, 1);
closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
closure->session = g_new0 (GSecretSession, 1);
g_simple_async_result_set_op_res_gpointer (res, closure, open_session_closure_free);
g_dbus_proxy_call (G_DBUS_PROXY (self), "OpenSession",
#ifdef WITH_GCRYPT
request_open_session_aes (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
cancellable, on_service_open_session_aes,
#else
request_open_session_plain (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
cancellable, on_service_open_session_plain,
#endif
g_object_ref (res));
/* Already have a session */
} else {
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
gsecret_service_ensure_session);
g_simple_async_result_complete_in_idle (res);
g_object_unref (res);
}
g_object_unref (res);
}
const gchar *
_gsecret_service_ensure_session_finish (GSecretService *self,
GAsyncResult *result,
GCancellable **cancellable,
GError **error)
{
OpenSessionClosure *closure;
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 (cancellable == NULL || *cancellable == NULL, NULL);
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
gsecret_service_ensure_session), NULL);
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
return NULL;
if (cancellable) {
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
*cancellable = closure->cancellable ? g_object_ref (closure->cancellable) : NULL;
}
/* The session we have should never change once created */
return gsecret_service_get_session_path (self);
}
const gchar *
@ -1111,7 +805,17 @@ gsecret_service_ensure_session_finish (GSecretService *self,
GAsyncResult *result,
GError **error)
{
return _gsecret_service_ensure_session_finish (self, result, NULL, error);
g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (!g_simple_async_result_is_valid (result, G_OBJECT (self),
gsecret_service_ensure_session)) {
if (!_gsecret_session_open_finish (result, error))
return NULL;
}
g_return_val_if_fail (self->pv->session != NULL, NULL);
return gsecret_service_get_session_path (self->pv->session);
}
const gchar *
@ -1142,328 +846,47 @@ gsecret_service_ensure_session_sync (GSecretService *self,
return path;
}
#ifdef WITH_GCRYPT
static gboolean
pkcs7_unpad_bytes_in_place (guchar *padded,
gsize *n_padded)
{
gsize n_pad, i;
if (*n_padded == 0)
return FALSE;
n_pad = padded[*n_padded - 1];
/* Validate the padding */
if (n_pad == 0 || n_pad > 16)
return FALSE;
if (n_pad > *n_padded)
return FALSE;
for (i = *n_padded - n_pad; i < *n_padded; ++i) {
if (padded[i] != n_pad)
return FALSE;
}
/* The last bit of data */
*n_padded -= n_pad;
/* Null teriminate as a courtesy */
padded[*n_padded] = 0;
return TRUE;
}
static GSecretValue *
service_decode_aes_secret (GSecretSession *session,
gconstpointer param,
gsize n_param,
gconstpointer value,
gsize n_value,
const gchar *content_type)
{
gcry_cipher_hd_t cih;
gsize n_padded;
gcry_error_t gcry;
guchar *padded;
gsize pos;
if (n_param != 16) {
g_message ("received an encrypted secret structure with invalid parameter");
return NULL;
}
if (n_value == 0 || n_value % 16 != 0) {
g_message ("received an encrypted secret structure with bad secret length");
return NULL;
}
gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
if (gcry != 0) {
g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
return NULL;
}
#if 0
g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
void
gsecret_service_ensure_collections (GSecretService *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
g_return_if_fail (GSECRET_IS_SERVICE (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
}
gboolean
gsecret_service_ensure_collections_finish (GSecretService *self,
GAsyncResult *result,
GError **error)
{
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_ensure_collections), FALSE);
}
gboolean
gsecret_service_ensure_collections_sync (GSecretService *self,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (GSECRET_IS_SERVICE (self), FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
}
#endif
gcry = gcry_cipher_setiv (cih, param, n_param);
g_return_val_if_fail (gcry == 0, NULL);
#if 0
g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
#endif
gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
g_return_val_if_fail (gcry == 0, NULL);
/* Copy the memory buffer */
n_padded = n_value;
padded = egg_secure_alloc (n_padded);
memcpy (padded, value, n_padded);
/* Perform the decryption */
for (pos = 0; pos < n_padded; pos += 16) {
gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
g_return_val_if_fail (gcry == 0, FALSE);
}
gcry_cipher_close (cih);
/* Unpad the resulting value */
if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) {
egg_secure_clear (padded, n_padded);
egg_secure_free (padded);
g_message ("received an invalid or unencryptable secret");
return FALSE;
}
return gsecret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
}
#endif /* WITH_GCRYPT */
static GSecretValue *
service_decode_plain_secret (GSecretSession *session,
gconstpointer param,
gsize n_param,
gconstpointer value,
gsize n_value,
const gchar *content_type)
{
if (n_param != 0) {
g_message ("received a plain secret structure with invalid parameter");
return NULL;
}
return gsecret_value_new (value, n_value, content_type);
}
GSecretValue *
_gsecret_service_decode_secret (GSecretService *self,
GVariant *encoded)
{
GSecretSession *session;
GSecretValue *result;
gconstpointer param;
gconstpointer value;
gchar *session_path;
gchar *content_type;
gsize n_param;
gsize n_value;
GVariant *vparam;
GVariant *vvalue;
g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL);
g_return_val_if_fail (encoded, NULL);
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
g_assert (session == NULL || session->path != NULL);
g_mutex_unlock (&self->pv->mutex);
g_return_val_if_fail (session != NULL, NULL);
/* Parsing (oayays) */
g_variant_get_child (encoded, 0, "o", &session_path);
if (session_path == NULL || !g_str_equal (session_path, session->path)) {
g_message ("received a secret encoded with wrong session: %s != %s",
session_path, session->path);
g_free (session_path);
return NULL;
}
vparam = g_variant_get_child_value (encoded, 1);
param = g_variant_get_fixed_array (vparam, &n_param, sizeof (guchar));
vvalue = g_variant_get_child_value (encoded, 2);
value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
g_variant_get_child (encoded, 3, "s", &content_type);
#ifdef WITH_GCRYPT
if (session->key != NULL)
result = service_decode_aes_secret (session, param, n_param,
value, n_value, content_type);
else
#endif
result = service_decode_plain_secret (session, param, n_param,
value, n_value, content_type);
g_variant_unref (vparam);
g_variant_unref (vvalue);
g_free (content_type);
g_free (session_path);
return result;
}
#ifdef WITH_GCRYPT
static guchar*
pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
gsize length,
gsize *n_padded)
{
gsize n_pad;
guchar *padded;
/* Pad the secret */
*n_padded = ((length + 16) / 16) * 16;
g_assert (length < *n_padded);
g_assert (*n_padded > 0);
n_pad = *n_padded - length;
g_assert (n_pad > 0 && n_pad <= 16);
padded = egg_secure_alloc (*n_padded);
memcpy (padded, secret, length);
memset (padded + length, n_pad, n_pad);
return padded;
}
static gboolean
service_encode_aes_secret (GSecretSession *session,
GSecretValue *value,
GVariantBuilder *builder)
{
gcry_cipher_hd_t cih;
guchar *padded;
gsize n_padded, pos;
gcry_error_t gcry;
gpointer iv;
gconstpointer secret;
gsize n_secret;
GVariant *child;
g_variant_builder_add (builder, "o", session->path);
/* Create the cipher */
gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
if (gcry != 0) {
g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
return FALSE;
}
secret = gsecret_value_get (value, &n_secret);
/* Perform the encoding here */
padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded);
g_assert (padded != NULL);
/* Setup the IV */
iv = g_malloc0 (16);
gcry_create_nonce (iv, 16);
gcry = gcry_cipher_setiv (cih, iv, 16);
g_return_val_if_fail (gcry == 0, FALSE);
/* Setup the key */
gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
g_return_val_if_fail (gcry == 0, FALSE);
/* Perform the encryption */
for (pos = 0; pos < n_padded; pos += 16) {
gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
g_return_val_if_fail (gcry == 0, FALSE);
}
gcry_cipher_close (cih);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value));
return TRUE;
}
#endif /* WITH_GCRYPT */
static gboolean
service_encode_plain_secret (GSecretSession *session,
GSecretValue *value,
GVariantBuilder *builder)
{
gconstpointer secret;
gsize n_secret;
GVariant *child;
g_variant_builder_add (builder, "o", session->path);
secret = gsecret_value_get (value, &n_secret);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE,
gsecret_value_unref, gsecret_value_ref (value));
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value));
return TRUE;
}
GVariant *
_gsecret_service_encode_secret (GSecretService *self,
GSecretValue *value)
{
GVariantBuilder *builder;
GSecretSession *session;
GVariant *result = NULL;
GVariantType *type;
gboolean ret;
g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL);
g_return_val_if_fail (value, NULL);
g_mutex_lock (&self->pv->mutex);
session = self->pv->session;
g_assert (session == NULL || session->path != NULL);
g_mutex_unlock (&self->pv->mutex);
g_return_val_if_fail (session != NULL, NULL);
type = g_variant_type_new ("(oayays)");
builder = g_variant_builder_new (type);
#ifdef WITH_GCRYPT
if (session->key)
ret = service_encode_aes_secret (session, value, builder);
else
#endif
ret = service_encode_plain_secret (session, value, builder);
if (ret)
result = g_variant_builder_end (builder);
g_variant_builder_unref (builder);
g_variant_type_free (type);
return result;
}
static void
on_search_items_complete (GObject *source,
GAsyncResult *result,
@ -1640,6 +1063,7 @@ search_load_item (GSecretService *self,
item = _gsecret_service_find_item_instance (self, path);
if (item == NULL) {
// TODO: xxxxxxxxxx;
gsecret_item_new (self, path, closure->cancellable,
on_search_loaded, g_object_ref (res));
closure->loading++;
@ -1875,14 +1299,16 @@ static GSecretValue *
service_decode_get_secrets_first (GSecretService *self,
GVariant *out)
{
GSecretSession *session;
GSecretValue *value;
GVariantIter *iter;
GVariant *variant;
GSecretValue *value;
const gchar *path;
g_variant_get (out, "(a{o(oayays)})", &iter);
while (g_variant_iter_next (iter, "{&o@(oayays)}", &path, &variant)) {
value = _gsecret_service_decode_secret (self, variant);
session = _gsecret_service_get_session (self);
value = _gsecret_session_decode_secret (session, variant);
g_variant_unref (variant);
break;
}
@ -1894,17 +1320,19 @@ static GHashTable *
service_decode_get_secrets_all (GSecretService *self,
GVariant *out)
{
GSecretSession *session;
GVariantIter *iter;
GVariant *variant;
GHashTable *values;
GSecretValue *value;
gchar *path;
session = _gsecret_service_get_session (self);
values = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, gsecret_value_unref);
g_variant_get (out, "(a{o(oayays)})", &iter);
while (g_variant_iter_loop (iter, "{o@(oayays)}", &path, &variant)) {
value = _gsecret_service_decode_secret (self, variant);
value = _gsecret_session_decode_secret (session, variant);
if (value && path)
g_hash_table_insert (values, g_strdup (path), value);
}
@ -2778,6 +2206,7 @@ gsecret_service_storev (GSecretService *self,
gpointer user_data)
{
GSimpleAsyncResult *res;
GSecretSession *session;
GVariant *attrs;
StoreClosure *closure;
GVariantBuilder builder;
@ -2808,9 +2237,10 @@ gsecret_service_storev (GSecretService *self,
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free);
session = _gsecret_service_get_session (self);
params = g_variant_new ("(&a{sv}&(oayays)b)",
g_variant_builder_end (&builder),
_gsecret_service_encode_secret (self, value),
_gsecret_session_encode_secret (session, value),
TRUE);
proxy = G_DBUS_PROXY (self);

View File

@ -1,6 +1,7 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@ -72,12 +73,12 @@ GSecretService * gsecret_service_get_finish (GAsyncResult
GSecretService * gsecret_service_get_sync (GCancellable *cancellable,
GError **error);
GList * gsecret_service_get_collections (GSecretService *self);
const gchar * gsecret_service_get_session_algorithms (GSecretService *self);
const gchar * gsecret_service_get_session_path (GSecretService *self);
GList * gsecret_service_get_collections (GSecretService *self);
void gsecret_service_ensure_session (GSecretService *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@ -91,6 +92,19 @@ const gchar * gsecret_service_ensure_session_sync (GSecretServi
GCancellable *cancellable,
GError **error);
void gsecret_service_ensure_collections (GSecretService *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean gsecret_service_ensure_collections_finish (GSecretService *self,
GAsyncResult *result,
GError **error);
gboolean gsecret_service_ensure_collections_sync (GSecretService *self,
GCancellable *cancellable,
GError **error);
void gsecret_service_search (GSecretService *self,
GHashTable *attributes,
GCancellable *cancellable,

671
library/gsecret-session.c Normal file
View File

@ -0,0 +1,671 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2011 Collabora Ltd.
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*/
#include "config.h"
#include "gsecret-private.h"
#ifdef WITH_GCRYPT
#include "egg/egg-dh.h"
#include "egg/egg-hkdf.h"
#include "egg/egg-libgcrypt.h"
#endif
#include "egg/egg-hex.h"
#include "egg/egg-secure-memory.h"
#include <glib/gi18n-lib.h>
EGG_SECURE_DECLARE (secret_session);
#define ALGORITHMS_AES "dh-ietf1024-sha256-aes128-cbc-pkcs7"
#define ALGORITHMS_PLAIN "plain"
struct _GSecretSession {
gchar *path;
const gchar *algorithms;
#ifdef WITH_GCRYPT
gcry_mpi_t prime;
gcry_mpi_t privat;
gcry_mpi_t publi;
#endif
gpointer key;
gsize n_key;
};
void
_gsecret_session_free (gpointer data)
{
GSecretSession *session = data;
if (session == NULL)
return;
g_free (session->path);
#ifdef WITH_GCRYPT
gcry_mpi_release (session->publi);
gcry_mpi_release (session->privat);
gcry_mpi_release (session->prime);
#endif
egg_secure_free (session->key);
g_free (session);
}
#ifdef WITH_GCRYPT
static GVariant *
request_open_session_aes (GSecretSession *session)
{
gcry_error_t gcry;
gcry_mpi_t base;
unsigned char *buffer;
size_t n_buffer;
GVariant *argument;
g_assert (session->prime == NULL);
g_assert (session->privat == NULL);
g_assert (session->publi == NULL);
/* Initialize our local parameters and values */
if (!egg_dh_default_params ("ietf-ike-grp-modp-1536",
&session->prime, &base))
g_return_val_if_reached (NULL);
#if 0
g_printerr ("\n lib prime: ");
gcry_mpi_dump (session->prime);
g_printerr ("\n lib base: ");
gcry_mpi_dump (base);
g_printerr ("\n");
#endif
if (!egg_dh_gen_pair (session->prime, base, 0,
&session->publi, &session->privat))
g_return_val_if_reached (NULL);
gcry_mpi_release (base);
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, session->publi);
g_return_val_if_fail (gcry == 0, NULL);
argument = g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
buffer, n_buffer, TRUE,
gcry_free, buffer);
return g_variant_new ("(sv)", ALGORITHMS_AES, argument);
}
static gboolean
response_open_session_aes (GSecretSession *session,
GVariant *response)
{
gconstpointer buffer;
GVariant *argument;
const gchar *sig;
gsize n_buffer;
gcry_mpi_t peer;
gcry_error_t gcry;
gpointer ikm;
gsize n_ikm;
sig = g_variant_get_type_string (response);
g_return_val_if_fail (sig != NULL, FALSE);
if (!g_str_equal (sig, "(vo)")) {
g_warning ("invalid OpenSession() response from daemon with signature: %s", sig);
return FALSE;
}
g_assert (session->path == NULL);
g_variant_get (response, "(vo)", &argument, &session->path);
buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar));
gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL);
g_return_val_if_fail (gcry == 0, FALSE);
g_variant_unref (argument);
#if 0
g_printerr (" lib publi: ");
gcry_mpi_dump (session->publi);
g_printerr ("\n lib peer: ");
gcry_mpi_dump (peer);
g_printerr ("\n");
#endif
ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm);
gcry_mpi_release (peer);
#if 0
g_printerr (" lib ikm: %s\n", egg_hex_encode (ikm, n_ikm));
#endif
if (ikm == NULL) {
g_warning ("couldn't negotiate a valid AES session key");
g_free (session->path);
session->path = NULL;
return FALSE;
}
session->n_key = 16;
session->key = egg_secure_alloc (session->n_key);
if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0,
session->key, session->n_key))
g_return_val_if_reached (FALSE);
egg_secure_free (ikm);
session->algorithms = ALGORITHMS_AES;
return TRUE;
}
#endif /* WITH_GCRYPT */
static GVariant *
request_open_session_plain (GSecretSession *session)
{
GVariant *argument = g_variant_new_string ("");
return g_variant_new ("(sv)", "plain", argument);
}
static gboolean
response_open_session_plain (GSecretSession *session,
GVariant *response)
{
GVariant *argument;
const gchar *sig;
sig = g_variant_get_type_string (response);
g_return_val_if_fail (sig != NULL, FALSE);
if (!g_str_equal (sig, "(vo)")) {
g_warning ("invalid OpenSession() response from daemon with signature: %s",
g_variant_get_type_string (response));
return FALSE;
}
g_assert (session->path == NULL);
g_variant_get (response, "(vo)", &argument, &session->path);
g_variant_unref (argument);
g_assert (session->key == NULL);
g_assert (session->n_key == 0);
session->algorithms = ALGORITHMS_PLAIN;
return TRUE;
}
typedef struct {
GCancellable *cancellable;
GSecretSession *session;
} OpenSessionClosure;
static void
open_session_closure_free (gpointer data)
{
OpenSessionClosure *closure = data;
g_assert (closure);
g_clear_object (&closure->cancellable);
_gsecret_session_free (closure->session);
g_free (closure);
}
static void
on_service_open_session_plain (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
OpenSessionClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretService *service = GSECRET_SERVICE (source);
GError *error = NULL;
GVariant *response;
response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error);
/* A successful response, decode it */
if (response != NULL) {
if (response_open_session_plain (closure->session, response)) {
_gsecret_service_take_session (service, closure->session);
closure->session = NULL;
} else {
g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL,
_("Couldn't communicate with the secret storage"));
}
g_simple_async_result_complete (res);
g_variant_unref (response);
} else {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
g_object_unref (res);
}
#ifdef WITH_GCRYPT
static void
on_service_open_session_aes (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
OpenSessionClosure * closure = g_simple_async_result_get_op_res_gpointer (res);
GSecretService *service = GSECRET_SERVICE (source);
GError *error = NULL;
GVariant *response;
response = g_dbus_proxy_call_finish (G_DBUS_PROXY (service), result, &error);
/* A successful response, decode it */
if (response != NULL) {
if (response_open_session_aes (closure->session, response)) {
_gsecret_service_take_session (service, closure->session);
closure->session = NULL;
} else {
g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL,
_("Couldn't communicate with the secret storage"));
}
g_simple_async_result_complete (res);
g_variant_unref (response);
} else {
/* AES session not supported, request a plain session */
if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) {
g_dbus_proxy_call (G_DBUS_PROXY (source), "OpenSession",
request_open_session_plain (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
closure->cancellable, on_service_open_session_plain,
g_object_ref (res));
g_error_free (error);
/* Other errors result in a failure */
} else {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
}
}
g_object_unref (res);
}
#endif /* WITH_GCRYPT */
void
_gsecret_session_open (GSecretService *service,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
OpenSessionClosure *closure;
res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
_gsecret_session_open);
closure = g_new (OpenSessionClosure, 1);
closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
closure->session = g_new0 (GSecretSession, 1);
g_simple_async_result_set_op_res_gpointer (res, closure, open_session_closure_free);
g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession",
#ifdef WITH_GCRYPT
request_open_session_aes (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
cancellable, on_service_open_session_aes,
#else
request_open_session_plain (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1,
cancellable, on_service_open_session_plain,
#endif
g_object_ref (res));
g_object_unref (res);
}
GSecretSession *
_gsecret_session_open_finish (GAsyncResult *result,
GError **error)
{
OpenSessionClosure *closure;
GSecretSession *session;
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
return NULL;
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
session = closure->session;
closure->session = NULL;
return session;
}
#ifdef WITH_GCRYPT
static gboolean
pkcs7_unpad_bytes_in_place (guchar *padded,
gsize *n_padded)
{
gsize n_pad, i;
if (*n_padded == 0)
return FALSE;
n_pad = padded[*n_padded - 1];
/* Validate the padding */
if (n_pad == 0 || n_pad > 16)
return FALSE;
if (n_pad > *n_padded)
return FALSE;
for (i = *n_padded - n_pad; i < *n_padded; ++i) {
if (padded[i] != n_pad)
return FALSE;
}
/* The last bit of data */
*n_padded -= n_pad;
/* Null teriminate as a courtesy */
padded[*n_padded] = 0;
return TRUE;
}
static GSecretValue *
service_decode_aes_secret (GSecretSession *session,
gconstpointer param,
gsize n_param,
gconstpointer value,
gsize n_value,
const gchar *content_type)
{
gcry_cipher_hd_t cih;
gsize n_padded;
gcry_error_t gcry;
guchar *padded;
gsize pos;
if (n_param != 16) {
g_message ("received an encrypted secret structure with invalid parameter");
return NULL;
}
if (n_value == 0 || n_value % 16 != 0) {
g_message ("received an encrypted secret structure with bad secret length");
return NULL;
}
gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
if (gcry != 0) {
g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
return NULL;
}
#if 0
g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
#endif
gcry = gcry_cipher_setiv (cih, param, n_param);
g_return_val_if_fail (gcry == 0, NULL);
#if 0
g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
#endif
gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
g_return_val_if_fail (gcry == 0, NULL);
/* Copy the memory buffer */
n_padded = n_value;
padded = egg_secure_alloc (n_padded);
memcpy (padded, value, n_padded);
/* Perform the decryption */
for (pos = 0; pos < n_padded; pos += 16) {
gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
g_return_val_if_fail (gcry == 0, FALSE);
}
gcry_cipher_close (cih);
/* Unpad the resulting value */
if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) {
egg_secure_clear (padded, n_padded);
egg_secure_free (padded);
g_message ("received an invalid or unencryptable secret");
return FALSE;
}
return gsecret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
}
#endif /* WITH_GCRYPT */
static GSecretValue *
service_decode_plain_secret (GSecretSession *session,
gconstpointer param,
gsize n_param,
gconstpointer value,
gsize n_value,
const gchar *content_type)
{
if (n_param != 0) {
g_message ("received a plain secret structure with invalid parameter");
return NULL;
}
return gsecret_value_new (value, n_value, content_type);
}
GSecretValue *
_gsecret_session_decode_secret (GSecretSession *session,
GVariant *encoded)
{
GSecretValue *result;
gconstpointer param;
gconstpointer value;
gchar *session_path;
gchar *content_type;
gsize n_param;
gsize n_value;
GVariant *vparam;
GVariant *vvalue;
g_return_val_if_fail (session != NULL, NULL);
g_return_val_if_fail (encoded != NULL, NULL);
/* Parsing (oayays) */
g_variant_get_child (encoded, 0, "o", &session_path);
if (session_path == NULL || !g_str_equal (session_path, session->path)) {
g_message ("received a secret encoded with wrong session: %s != %s",
session_path, session->path);
g_free (session_path);
return NULL;
}
vparam = g_variant_get_child_value (encoded, 1);
param = g_variant_get_fixed_array (vparam, &n_param, sizeof (guchar));
vvalue = g_variant_get_child_value (encoded, 2);
value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
g_variant_get_child (encoded, 3, "s", &content_type);
#ifdef WITH_GCRYPT
if (session->key != NULL)
result = service_decode_aes_secret (session, param, n_param,
value, n_value, content_type);
else
#endif
result = service_decode_plain_secret (session, param, n_param,
value, n_value, content_type);
g_variant_unref (vparam);
g_variant_unref (vvalue);
g_free (content_type);
g_free (session_path);
return result;
}
#ifdef WITH_GCRYPT
static guchar*
pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
gsize length,
gsize *n_padded)
{
gsize n_pad;
guchar *padded;
/* Pad the secret */
*n_padded = ((length + 16) / 16) * 16;
g_assert (length < *n_padded);
g_assert (*n_padded > 0);
n_pad = *n_padded - length;
g_assert (n_pad > 0 && n_pad <= 16);
padded = egg_secure_alloc (*n_padded);
memcpy (padded, secret, length);
memset (padded + length, n_pad, n_pad);
return padded;
}
static gboolean
service_encode_aes_secret (GSecretSession *session,
GSecretValue *value,
GVariantBuilder *builder)
{
gcry_cipher_hd_t cih;
guchar *padded;
gsize n_padded, pos;
gcry_error_t gcry;
gpointer iv;
gconstpointer secret;
gsize n_secret;
GVariant *child;
g_variant_builder_add (builder, "o", session->path);
/* Create the cipher */
gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0);
if (gcry != 0) {
g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry));
return FALSE;
}
secret = gsecret_value_get (value, &n_secret);
/* Perform the encoding here */
padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded);
g_assert (padded != NULL);
/* Setup the IV */
iv = g_malloc0 (16);
gcry_create_nonce (iv, 16);
gcry = gcry_cipher_setiv (cih, iv, 16);
g_return_val_if_fail (gcry == 0, FALSE);
/* Setup the key */
gcry = gcry_cipher_setkey (cih, session->key, session->n_key);
g_return_val_if_fail (gcry == 0, FALSE);
/* Perform the encryption */
for (pos = 0; pos < n_padded; pos += 16) {
gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0);
g_return_val_if_fail (gcry == 0, FALSE);
}
gcry_cipher_close (cih);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value));
return TRUE;
}
#endif /* WITH_GCRYPT */
static gboolean
service_encode_plain_secret (GSecretSession *session,
GSecretValue *value,
GVariantBuilder *builder)
{
gconstpointer secret;
gsize n_secret;
GVariant *child;
g_variant_builder_add (builder, "o", session->path);
secret = gsecret_value_get (value, &n_secret);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL);
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE,
gsecret_value_unref, gsecret_value_ref (value));
g_variant_builder_add_value (builder, child);
g_variant_unref (child);
g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value));
return TRUE;
}
GVariant *
_gsecret_session_encode_secret (GSecretSession *session,
GSecretValue *value)
{
GVariantBuilder *builder;
GVariant *result = NULL;
GVariantType *type;
gboolean ret;
g_return_val_if_fail (session != NULL, NULL);
g_return_val_if_fail (value != NULL, NULL);
type = g_variant_type_new ("(oayays)");
builder = g_variant_builder_new (type);
#ifdef WITH_GCRYPT
if (session->key)
ret = service_encode_aes_secret (session, value, builder);
else
#endif
ret = service_encode_plain_secret (session, value, builder);
if (ret)
result = g_variant_builder_end (builder);
g_variant_builder_unref (builder);
g_variant_type_free (type);
return result;
}
const gchar *
_gsecret_session_get_algorithms (GSecretSession *session)
{
g_return_val_if_fail (session != NULL, NULL);
return session->algorithms;
}
const gchar *
_gsecret_session_get_path (GSecretSession *session)
{
g_return_val_if_fail (session != NULL, NULL);
return session->path;
}

View File

@ -118,7 +118,7 @@ _gsecret_util_attributes_for_variant (GVariant *variant)
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))
while (g_variant_iter_next (&iter, "{ss}", &key, &value))
g_hash_table_insert (attributes, key, value);
return attributes;
@ -288,6 +288,20 @@ _gsecret_util_get_properties_finish (GDBusProxy *proxy,
return TRUE;
}
typedef struct {
gchar *property;
GVariant *value;
gboolean result;
} SetClosure;
static void
set_closure_free (gpointer data)
{
SetClosure *closure = data;
g_free (closure->property);
g_variant_unref (closure->value);
g_slice_free (SetClosure, closure);
}
static void
on_set_property (GObject *source,
@ -295,6 +309,8 @@ on_set_property (GObject *source,
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
SetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
GDBusProxy *proxy = G_DBUS_PROXY (g_async_result_get_source_object (user_data));
GError *error = NULL;
GVariant *retval;
@ -304,7 +320,13 @@ on_set_property (GObject *source,
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);
closure->result = retval != NULL;
if (closure->result)
g_dbus_proxy_set_cached_property (proxy, closure->property, closure->value);
g_simple_async_result_complete (res);
g_object_unref (proxy);
g_object_unref (res);
}
@ -318,10 +340,15 @@ _gsecret_util_set_property (GDBusProxy *proxy,
gpointer user_data)
{
GSimpleAsyncResult *res;
SetClosure *closure;
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = g_simple_async_result_new (G_OBJECT (proxy), callback, user_data, result_tag);
closure = g_slice_new0 (SetClosure);
closure->property = g_strdup (property);
closure->value = g_variant_ref_sink (value);
g_simple_async_result_set_op_res_gpointer (res, closure, set_closure_free);
g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
g_dbus_proxy_get_name (proxy),
@ -331,7 +358,7 @@ _gsecret_util_set_property (GDBusProxy *proxy,
g_variant_new ("(ssv)",
g_dbus_proxy_get_interface_name (proxy),
property,
value),
closure->value),
G_VARIANT_TYPE ("()"),
G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
cancellable, on_set_property,
@ -347,6 +374,7 @@ _gsecret_util_set_property_finish (GDBusProxy *proxy,
GError **error)
{
GSimpleAsyncResult *res;
SetClosure *closure;
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);
@ -356,7 +384,8 @@ _gsecret_util_set_property_finish (GDBusProxy *proxy,
if (g_simple_async_result_propagate_error (res, error))
return FALSE;
return g_simple_async_result_get_op_res_gboolean (res);
closure = g_simple_async_result_get_op_res_gpointer (res);
return closure->result;
}
gboolean
@ -366,11 +395,14 @@ _gsecret_util_set_property_sync (GDBusProxy *proxy,
GCancellable *cancellable,
GError **error)
{
gboolean result = FALSE;
GVariant *retval;
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_variant_ref_sink (value);
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),
@ -384,10 +416,26 @@ _gsecret_util_set_property_sync (GDBusProxy *proxy,
G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
cancellable, error);
if (retval != NULL)
if (retval != NULL) {
result = TRUE;
g_variant_unref (retval);
g_dbus_proxy_set_cached_property (proxy, property, value);
}
return (retval != NULL);
g_variant_unref (value);
return result;
}
gboolean
_gsecret_util_have_cached_properties (GDBusProxy *proxy)
{
gchar **names;
names = g_dbus_proxy_get_cached_property_names (proxy);
g_strfreev (names);
return names != NULL;
}
GSecretSync *

View File

@ -19,7 +19,7 @@
G_BEGIN_DECLS
#define GSECRET_TYPE_VALUE (gsecret_service_get_type ())
#define GSECRET_TYPE_VALUE (gsecret_value_get_type ())
GType gsecret_value_get_type (void) G_GNUC_CONST;

View File

@ -26,10 +26,13 @@ LDADD = \
$(NULL)
TEST_PROGS = \
test-value \
test-prompt \
test-service \
test-session \
test-password \
test-item \
test-collection \
$(NULL)
check_PROGRAMS = \

View File

@ -149,8 +149,9 @@ class SecretSession(dbus.service.Object):
(params, data) = self.algorithm.encrypt(self.key, secret)
# print " mock iv: ", hex_encode(params)
# print " mock ciph: ", hex_encode(data)
return dbus.Struct((self.path, dbus.ByteArray(params), dbus.ByteArray(data),
dbus.String(content_type)), signature="oayays")
return dbus.Struct((dbus.ObjectPath(self.path), dbus.ByteArray(params),
dbus.ByteArray(data), dbus.String(content_type)),
signature="oayays")
@dbus.service.method('org.freedesktop.Secret.Session')
def Close(self):
@ -167,9 +168,9 @@ class SecretItem(dbus.service.Object):
self.secret = secret
self.attributes = attributes
self.content_type = content_type
self.locked = collection.locked
self.path = "%s/%s" % (collection.path, identifier)
self.confirm = confirm
self.created = self.modified = time.time()
dbus.service.Object.__init__(self, collection.service.bus_name, self.path)
collection.items[identifier] = self
objects[self.path] = self
@ -183,13 +184,14 @@ class SecretItem(dbus.service.Object):
def perform_delete(self):
del self.collection.items[self.identifier]
del objects[self.path]
self.remove_from_connection()
@dbus.service.method('org.freedesktop.Secret.Item', sender_keyword='sender')
def GetSecret(self, session_path, sender=None):
session = objects.get(session_path, None)
if not session or session.sender != sender:
raise InvalidArgs("session invalid: %s" % session_path)
if self.locked:
if self.collection.locked:
raise IsLocked("secret is locked: %s" % self.path)
return session.encode_secret(self.secret, self.content_type)
@ -203,14 +205,49 @@ class SecretItem(dbus.service.Object):
self.perform_delete()
return dbus.ObjectPath("/")
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
return self.GetAll(interface_name)[property_name]
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
if interface_name == 'org.freedesktop.Secret.Item':
return {
'Locked': self.collection.locked,
'Attributes': dbus.Dictionary(self.attributes, signature='ss'),
'Label': self.label,
'Created': dbus.UInt64(self.created),
'Modified': dbus.UInt64(self.modified)
}
else:
raise InvalidArgs('Unknown %s interface' % interface_name)
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ssv')
def Set(self, interface_name, property_name, new_value):
if interface_name != 'org.freedesktop.Secret.Item':
raise InvalidArgs('Unknown %s interface' % interface_name)
if property_name == "Label":
self.label = str(new_value)
elif property_name == "Attributes":
self.attributes = dict(new_value)
else:
raise InvalidArgs('Unknown %s interface' % property_name)
self.PropertiesChanged(interface_name, { property_name: new_value }, [])
@dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
def PropertiesChanged(self, interface_name, changed_properties, invalidated_properties):
self.modified = time.time()
class SecretCollection(dbus.service.Object):
def __init__(self, service, identifier, label="Collection", locked=False):
def __init__(self, service, identifier, label="Collection", locked=False, confirm=False):
self.service = service
self.identifier = identifier
self.label = label
self.locked = locked
self.items = { }
self.confirm = confirm
self.created = self.modified = time.time()
self.path = "%s%s" % (COLLECTION_PREFIX, identifier)
dbus.service.Object.__init__(self, service.bus_name, self.path)
service.collections[identifier] = self
@ -223,6 +260,54 @@ class SecretCollection(dbus.service.Object):
results.append(item)
return results
def perform_delete(self):
for item in self.items.values():
item.perform_delete()
del self.service.collections[self.identifier]
del objects[self.path]
self.remove_from_connection()
@dbus.service.method('org.freedesktop.Secret.Collection', sender_keyword='sender')
def Delete(self, sender=None):
if self.confirm:
prompt = SecretPrompt(self.collection.service, sender,
dismiss=False, action=self.perform_delete)
return dbus.ObjectPath(prompt.path)
else:
self.perform_delete()
return dbus.ObjectPath("/")
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
def Get(self, interface_name, property_name):
return self.GetAll(interface_name)[property_name]
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name):
if interface_name == 'org.freedesktop.Secret.Collection':
return {
'Locked': self.locked,
'Label': self.label,
'Created': dbus.UInt64(self.created),
'Modified': dbus.UInt64(self.modified),
'Items': [dbus.ObjectPath(i.path) for i in self.items.values()]
}
else:
raise InvalidArgs('Unknown %s interface' % interface_name)
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ssv')
def Set(self, interface_name, property_name, new_value):
if interface_name != 'org.freedesktop.Secret.Collection':
raise InvalidArgs('Unknown %s interface' % interface_name)
if property_name == "Label":
self.label = str(new_value)
else:
raise InvalidArgs('Unknown %s interface' % property_name)
self.PropertiesChanged(interface_name, { property_name: new_value }, [])
@dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
def PropertiesChanged(self, interface_name, changed_properties, invalidated_properties):
self.modified = time.time()
class SecretService(dbus.service.Object):
@ -251,8 +336,8 @@ class SecretService(dbus.service.Object):
'org.freedesktop.DBus')
def add_standard_objects(self):
collection = SecretCollection(self, "collection", locked=False)
SecretItem(collection, "item_one", attributes={ "number": "1", "string": "one", "parity": "odd" }, secret="uno")
collection = SecretCollection(self, "collection", label="Collection One", locked=False)
SecretItem(collection, "item_one", label="Item One", attributes={ "number": "1", "string": "one", "parity": "odd" }, secret="uno")
SecretItem(collection, "item_two", attributes={ "number": "2", "string": "two", "parity": "even" }, secret="dos")
SecretItem(collection, "item_three", attributes={ "number": "3", "string": "three", "parity": "odd" }, secret="tres")
@ -323,7 +408,7 @@ class SecretService(dbus.service.Object):
results = dbus.Dictionary(signature="o(oayays)")
for item_path in item_paths:
item = objects.get(item_path, None)
if item and not item.locked:
if item and not item.collection.locked:
results[item_path] = item.GetSecret(session_path, sender)
return results

View File

@ -0,0 +1,339 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*
* Author: Stef Walter <stefw@gnome.org>
*/
#include "config.h"
#include "gsecret-collection.h"
#include "gsecret-service.h"
#include "gsecret-private.h"
#include "mock-service.h"
#include "egg/egg-testing.h"
#include <glib.h>
#include <errno.h>
#include <stdlib.h>
typedef struct {
GDBusConnection *connection;
GSecretService *service;
} Test;
static void
setup (Test *test,
gconstpointer data)
{
GError *error = NULL;
const gchar *mock_script = data;
mock_service_start (mock_script, &error);
g_assert_no_error (error);
test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
test->service = _gsecret_service_bare_instance (test->connection, NULL);
}
static void
teardown (Test *test,
gconstpointer unused)
{
GError *error = NULL;
g_object_unref (test->service);
egg_assert_not_object (test->service);
mock_service_stop ();
g_dbus_connection_flush_sync (test->connection, NULL, &error);
g_assert_no_error (error);
g_object_unref (test->connection);
}
static void
on_async_result (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GAsyncResult **ret = user_data;
g_assert (ret != NULL);
g_assert (*ret == NULL);
*ret = g_object_ref (result);
egg_test_wait_stop ();
}
static void
on_notify_stop (GObject *obj,
GParamSpec *spec,
gpointer user_data)
{
guint *sigs = user_data;
g_assert (sigs != NULL);
g_assert (*sigs > 0);
if (--(*sigs) == 0)
egg_test_wait_stop ();
}
static void
test_new_sync (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GError *error = NULL;
GSecretCollection *collection;
collection = gsecret_collection_new_sync (test->service, collection_path, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), ==, collection_path);
g_object_unref (collection);
egg_assert_not_object (collection);
}
static void
test_new_async (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GError *error = NULL;
GSecretCollection *collection;
GAsyncResult *result = NULL;
gsecret_collection_new (test->service, collection_path, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
collection = gsecret_collection_new_finish (result, &error);
g_assert_no_error (error);
g_object_unref (result);
g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection)), ==, collection_path);
g_object_unref (collection);
egg_assert_not_object (collection);
}
static void
test_properties (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GError *error = NULL;
GSecretCollection *collection;
guint64 created;
guint64 modified;
gboolean locked;
gchar *label;
collection = gsecret_collection_new_sync (test->service, collection_path, NULL, &error);
g_assert_no_error (error);
g_assert (gsecret_collection_get_locked (collection) == FALSE);
g_assert_cmpuint (gsecret_collection_get_created (collection), <=, time (NULL));
g_assert_cmpuint (gsecret_collection_get_modified (collection), <=, time (NULL));
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Collection One");
g_free (label);
g_object_get (collection,
"locked", &locked,
"created", &created,
"modified", &modified,
"label", &label,
NULL);
g_assert (locked == FALSE);
g_assert_cmpuint (created, <=, time (NULL));
g_assert_cmpuint (modified, <=, time (NULL));
g_assert_cmpstr (label, ==, "Collection One");
g_free (label);
g_object_unref (collection);
}
static void
test_set_label_sync (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GError *error = NULL;
GSecretCollection *collection;
gboolean ret;
gchar *label;
collection = gsecret_collection_new_sync (test->service, collection_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Collection One");
g_free (label);
ret = gsecret_collection_set_label_sync (collection, "Another label", NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Another label");
g_free (label);
g_object_unref (collection);
}
static void
test_set_label_async (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretCollection *collection;
gboolean ret;
gchar *label;
collection = gsecret_collection_new_sync (test->service, collection_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Collection One");
g_free (label);
gsecret_collection_set_label (collection, "Another label", NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
ret = gsecret_collection_set_label_finish (collection, result, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (result);
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Another label");
g_free (label);
g_object_unref (collection);
}
static void
test_set_label_prop (Test *test,
gconstpointer unused)
{
const gchar *collection_path = "/org/freedesktop/secrets/collection/collection";
GError *error = NULL;
GSecretCollection *collection;
guint sigs = 2;
gchar *label;
collection = gsecret_collection_new_sync (test->service, collection_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Collection One");
g_free (label);
g_signal_connect (collection, "notify::label", G_CALLBACK (on_notify_stop), &sigs);
g_object_set (collection, "label", "Blah blah", NULL);
/* Wait for the property to actually 'take' */
egg_test_wait ();
label = gsecret_collection_get_label (collection);
g_assert_cmpstr (label, ==, "Blah blah");
g_free (label);
g_object_unref (collection);
}
#if 0
static void
test_delete_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
gboolean ret;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
ret = gsecret_item_delete_sync (item, NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (item);
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_assert (item == NULL);
}
static void
test_delete_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretItem *item;
gboolean ret;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
gsecret_item_delete (item, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
ret = gsecret_item_delete_finish (item, result, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (item);
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_assert (item == NULL);
}
#endif
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_set_prgname ("test-collection");
g_type_init ();
g_test_add ("/collection/new-sync", Test, "mock-service-normal.py", setup, test_new_sync, teardown);
g_test_add ("/collection/new-async", Test, "mock-service-normal.py", setup, test_new_async, teardown);
g_test_add ("/collection/properties", Test, "mock-service-normal.py", setup, test_properties, teardown);
g_test_add ("/collection/set-label-sync", Test, "mock-service-normal.py", setup, test_set_label_sync, teardown);
g_test_add ("/collection/set-label-async", Test, "mock-service-normal.py", setup, test_set_label_async, teardown);
g_test_add ("/collection/set-label-prop", Test, "mock-service-normal.py", setup, test_set_label_prop, teardown);
#if 0
g_test_add ("/item/delete-sync", Test, "mock-service-normal.py", setup, test_delete_sync, teardown);
g_test_add ("/item/delete-async", Test, "mock-service-normal.py", setup, test_delete_async, teardown);
#endif
return egg_tests_run_with_loop ();
}

534
library/tests/test-item.c Normal file
View File

@ -0,0 +1,534 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*
* Author: Stef Walter <stefw@gnome.org>
*/
#include "config.h"
#include "gsecret-item.h"
#include "gsecret-service.h"
#include "gsecret-private.h"
#include "mock-service.h"
#include "egg/egg-testing.h"
#include <glib.h>
#include <errno.h>
#include <stdlib.h>
typedef struct {
GDBusConnection *connection;
GSecretService *service;
} Test;
static void
setup (Test *test,
gconstpointer data)
{
GError *error = NULL;
const gchar *mock_script = data;
mock_service_start (mock_script, &error);
g_assert_no_error (error);
test->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
g_assert_no_error (error);
test->service = _gsecret_service_bare_instance (test->connection, NULL);
}
static void
teardown (Test *test,
gconstpointer unused)
{
GError *error = NULL;
g_object_unref (test->service);
egg_assert_not_object (test->service);
mock_service_stop ();
g_dbus_connection_flush_sync (test->connection, NULL, &error);
g_assert_no_error (error);
g_object_unref (test->connection);
}
static void
on_async_result (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GAsyncResult **ret = user_data;
g_assert (ret != NULL);
g_assert (*ret == NULL);
*ret = g_object_ref (result);
egg_test_wait_stop ();
}
static void
on_notify_stop (GObject *obj,
GParamSpec *spec,
gpointer user_data)
{
guint *sigs = user_data;
g_assert (sigs != NULL);
g_assert (*sigs > 0);
if (--(*sigs) == 0)
egg_test_wait_stop ();
g_printerr ("sigs: %u\n", *sigs);
}
static void
test_new_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), ==, item_path);
g_object_unref (item);
}
static void
test_new_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretItem *item;
gsecret_item_new (test->service, item_path, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
item = gsecret_item_new_finish (result, &error);
g_assert_no_error (error);
g_object_unref (result);
g_assert_cmpstr (g_dbus_proxy_get_object_path (G_DBUS_PROXY (item)), ==, item_path);
g_object_unref (item);
}
static void
test_properties (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GHashTable *attributes;
GSecretItem *item;
guint64 created;
guint64 modified;
gboolean locked;
gchar *label;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
g_assert (gsecret_item_get_locked (item) == FALSE);
g_assert_cmpuint (gsecret_item_get_created (item), <=, time (NULL));
g_assert_cmpuint (gsecret_item_get_modified (item), <=, time (NULL));
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Item One");
g_free (label);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1");
g_assert_cmpstr (g_hash_table_lookup (attributes, "parity"), ==, "odd");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 3);
g_hash_table_unref (attributes);
g_object_get (item,
"locked", &locked,
"created", &created,
"modified", &modified,
"label", &label,
"attributes", &attributes,
NULL);
g_assert (locked == FALSE);
g_assert_cmpuint (created, <=, time (NULL));
g_assert_cmpuint (modified, <=, time (NULL));
g_assert_cmpstr (label, ==, "Item One");
g_free (label);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1");
g_assert_cmpstr (g_hash_table_lookup (attributes, "parity"), ==, "odd");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 3);
g_hash_table_unref (attributes);
g_object_unref (item);
}
static void
test_set_label_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
gboolean ret;
gchar *label;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Item One");
g_free (label);
ret = gsecret_item_set_label_sync (item, "Another label", NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Another label");
g_free (label);
g_object_unref (item);
}
static void
test_set_label_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretItem *item;
gboolean ret;
gchar *label;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Item One");
g_free (label);
gsecret_item_set_label (item, "Another label", NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
ret = gsecret_item_set_label_finish (item, result, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (result);
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Another label");
g_free (label);
g_object_unref (item);
}
static void
test_set_label_prop (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
guint sigs = 2;
gchar *label;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Item One");
g_free (label);
g_signal_connect (item, "notify::label", G_CALLBACK (on_notify_stop), &sigs);
g_object_set (item, "label", "Blah blah", NULL);
/* Wait for the property to actually 'take' */
egg_test_wait ();
label = gsecret_item_get_label (item);
g_assert_cmpstr (label, ==, "Blah blah");
g_free (label);
g_object_unref (item);
}
static void
test_set_attributes_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
gboolean ret;
GHashTable *attributes;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1");
g_assert_cmpstr (g_hash_table_lookup (attributes, "parity"), ==, "odd");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 3);
g_hash_table_unref (attributes);
attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "string", "five");
g_hash_table_insert (attributes, "number", "5");
ret = gsecret_item_set_attributes_sync (item, attributes, NULL, &error);
g_hash_table_unref (attributes);
g_assert_no_error (error);
g_assert (ret == TRUE);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 2);
g_hash_table_unref (attributes);
g_object_unref (item);
}
static void
test_set_attributes_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GHashTable *attributes;
GError *error = NULL;
GAsyncResult *result = NULL;
GSecretItem *item;
gboolean ret;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1");
g_assert_cmpstr (g_hash_table_lookup (attributes, "parity"), ==, "odd");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 3);
g_hash_table_unref (attributes);
attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "string", "five");
g_hash_table_insert (attributes, "number", "5");
gsecret_item_set_attributes (item, attributes, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
ret = gsecret_item_set_attributes_finish (item, result, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (result);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 2);
g_hash_table_unref (attributes);
g_object_unref (item);
}
static void
test_set_attributes_prop (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
GHashTable *attributes;
guint sigs = 2;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "one");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "1");
g_assert_cmpstr (g_hash_table_lookup (attributes, "parity"), ==, "odd");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 3);
g_hash_table_unref (attributes);
g_signal_connect (item, "notify::attributes", G_CALLBACK (on_notify_stop), &sigs);
attributes = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (attributes, "string", "five");
g_hash_table_insert (attributes, "number", "5");
g_object_set (item, "attributes", attributes, NULL);
g_hash_table_unref (attributes);
/* Wait for the property to actually 'take' */
egg_test_wait ();
attributes = gsecret_item_get_attributes (item);
g_assert_cmpstr (g_hash_table_lookup (attributes, "string"), ==, "five");
g_assert_cmpstr (g_hash_table_lookup (attributes, "number"), ==, "5");
g_assert_cmpuint (g_hash_table_size (attributes), ==, 2);
g_hash_table_unref (attributes);
g_object_unref (item);
}
static void
test_get_secret_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
GSecretValue *value;
gconstpointer data;
gsize length;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
value = gsecret_item_get_secret_sync (item, NULL, &error);
g_assert_no_error (error);
g_assert (value != NULL);
data = gsecret_value_get (value, &length);
egg_assert_cmpmem (data, length, ==, "uno", 3);
gsecret_value_unref (value);
g_object_unref (item);
}
static void
test_get_secret_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretItem *item;
GSecretValue *value;
gconstpointer data;
gsize length;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
gsecret_item_get_secret (item, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
value = gsecret_item_get_secret_finish (item, result, &error);
g_assert_no_error (error);
g_assert (value != NULL);
g_object_unref (result);
data = gsecret_value_get (value, &length);
egg_assert_cmpmem (data, length, ==, "uno", 3);
gsecret_value_unref (value);
g_object_unref (item);
}
static void
test_delete_sync (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GError *error = NULL;
GSecretItem *item;
gboolean ret;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
ret = gsecret_item_delete_sync (item, NULL, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (item);
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_assert (item == NULL);
}
static void
test_delete_async (Test *test,
gconstpointer unused)
{
const gchar *item_path = "/org/freedesktop/secrets/collection/collection/item_one";
GAsyncResult *result = NULL;
GError *error = NULL;
GSecretItem *item;
gboolean ret;
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_no_error (error);
gsecret_item_delete (item, NULL, on_async_result, &result);
g_assert (result == NULL);
egg_test_wait ();
ret = gsecret_item_delete_finish (item, result, &error);
g_assert_no_error (error);
g_assert (ret == TRUE);
g_object_unref (item);
item = gsecret_item_new_sync (test->service, item_path, NULL, &error);
g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
g_assert (item == NULL);
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_set_prgname ("test-item");
g_type_init ();
g_test_add ("/item/new-sync", Test, "mock-service-normal.py", setup, test_new_sync, teardown);
g_test_add ("/item/new-async", Test, "mock-service-normal.py", setup, test_new_async, teardown);
g_test_add ("/item/properties", Test, "mock-service-normal.py", setup, test_properties, teardown);
g_test_add ("/item/set-label-sync", Test, "mock-service-normal.py", setup, test_set_label_sync, teardown);
g_test_add ("/item/set-label-async", Test, "mock-service-normal.py", setup, test_set_label_async, teardown);
g_test_add ("/item/set-attributes-sync", Test, "mock-service-normal.py", setup, test_set_attributes_sync, teardown);
g_test_add ("/item/set-attributes-async", Test, "mock-service-normal.py", setup, test_set_attributes_async, teardown);
g_test_add ("/item/get-secret-sync", Test, "mock-service-normal.py", setup, test_get_secret_sync, teardown);
g_test_add ("/item/get-secret-async", Test, "mock-service-normal.py", setup, test_get_secret_async, teardown);
g_test_add ("/item/delete-sync", Test, "mock-service-normal.py", setup, test_delete_sync, teardown);
g_test_add ("/item/delete-async", Test, "mock-service-normal.py", setup, test_delete_async, teardown);
g_test_add ("/item/set-attributes-prop", Test, "mock-service-normal.py", setup, test_set_attributes_prop, teardown);
g_test_add ("/item/set-label-prop", Test, "mock-service-normal.py", setup, test_set_label_prop, teardown);
return egg_tests_run_with_loop ();
}

210
library/tests/test-value.c Normal file
View File

@ -0,0 +1,210 @@
/* GSecret - GLib wrapper for Secret Service
*
* Copyright 2012 Red Hat Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*/
#include "config.h"
#include "gsecret-value.h"
#include "gsecret-private.h"
#include "egg/egg-testing.h"
#include "egg/egg-secure-memory.h"
#include <glib.h>
#include <errno.h>
#include <stdlib.h>
EGG_SECURE_DECLARE (test_value);
static void
test_new (void)
{
GSecretValue *value;
gsize length;
value = gsecret_value_new ("blahblah", 4, "text/plain");
g_assert_cmpstr (gsecret_value_get (value, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
g_assert_cmpstr (gsecret_value_get_content_type (value), ==, "text/plain");
gsecret_value_unref (value);
}
static void
test_new_terminated (void)
{
GSecretValue *value;
gsize length;
value = gsecret_value_new ("blah", -1, "text/plain");
g_assert_cmpstr (gsecret_value_get (value, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
g_assert_cmpstr (gsecret_value_get_content_type (value), ==, "text/plain");
gsecret_value_unref (value);
}
static void
test_new_full (void)
{
GSecretValue *value;
gchar *data = g_strdup ("blah");
gsize length;
value = gsecret_value_new_full (data, 4, "text/plain", g_free);
g_assert_cmpstr (gsecret_value_get (value, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
/* No copy done here */
g_assert (gsecret_value_get (value, NULL) == data);
gsecret_value_unref (value);
}
static void
test_new_full_terminated (void)
{
GSecretValue *value;
gchar *data = g_strdup ("blah");
gsize length;
value = gsecret_value_new_full (data, -1, "text/plain", g_free);
g_assert_cmpstr (gsecret_value_get (value, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
/* No copy done here */
g_assert (gsecret_value_get (value, NULL) == data);
gsecret_value_unref (value);
}
static void
test_ref_unref (void)
{
GSecretValue *value;
GSecretValue *value2;
gsize length;
value = gsecret_value_new ("blah", 4, "text/plain");
value2 = gsecret_value_ref(value);
gsecret_value_unref (value);
g_assert_cmpstr (gsecret_value_get (value2, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
gsecret_value_unref (value2);
}
static void
test_boxed (void)
{
GSecretValue *value;
GSecretValue *value2;
gsize length;
value = gsecret_value_new ("blah", 4, "text/plain");
value2 = g_boxed_copy (GSECRET_TYPE_VALUE, value);
g_boxed_free (GSECRET_TYPE_VALUE, value);
g_assert_cmpstr (gsecret_value_get (value2, &length), ==, "blah");
g_assert_cmpuint (length, ==, 4);
g_boxed_free (GSECRET_TYPE_VALUE, value2);
}
static void
test_to_password (void)
{
GSecretValue *value;
gchar *password;
value = gsecret_value_new_full (egg_secure_strdup ("blah"), -1,
"text/plain", egg_secure_free);
password = _gsecret_value_unref_to_password (value);
g_assert_cmpstr (password, ==, "blah");
egg_secure_free (password);
}
static void
test_to_password_bad_destroy (void)
{
GSecretValue *value;
gchar *password;
value = gsecret_value_new_full (g_strdup ("blah"), -1,
"text/plain", g_free);
password = _gsecret_value_unref_to_password (value);
g_assert_cmpstr (password, ==, "blah");
egg_secure_free (password);
}
static void
test_to_password_bad_content (void)
{
GSecretValue *value;
gchar *password;
value = gsecret_value_new_full (g_strdup ("wooowhee"), -1,
"application/octet-stream", g_free);
password = _gsecret_value_unref_to_password (value);
g_assert_cmpstr (password, ==, NULL);
}
static void
test_to_password_extra_ref (void)
{
GSecretValue *value;
gchar *password;
value = gsecret_value_new_full (egg_secure_strdup ("blah"), -1,
"text/plain", egg_secure_free);
gsecret_value_ref (value);
password = _gsecret_value_unref_to_password (value);
g_assert_cmpstr (password, ==, "blah");
egg_secure_free (password);
gsecret_value_unref (value);
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_set_prgname ("test-value");
g_type_init ();
g_test_add_func ("/value/new", test_new);
g_test_add_func ("/value/new-terminated", test_new_terminated);
g_test_add_func ("/value/new-full", test_new_full);
g_test_add_func ("/value/new-full-terminated", test_new_full_terminated);
g_test_add_func ("/value/ref-unref", test_ref_unref);
g_test_add_func ("/value/boxed", test_boxed);
g_test_add_func ("/value/to-password", test_to_password);
g_test_add_func ("/value/to-password-bad-destroy", test_to_password_bad_destroy);
g_test_add_func ("/value/to-password-bad-content", test_to_password_bad_content);
g_test_add_func ("/value/to-password-extra-ref", test_to_password_extra_ref);
return egg_tests_run_with_loop ();
}