mirror of
https://gitlab.gnome.org/GNOME/libsecret.git
synced 2024-12-22 04:38:55 +00:00
Tests for GSecretItem and GSecretValue
* And fix bugs found in the process
This commit is contained in:
parent
116447c59e
commit
f44aae6efa
@ -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) \
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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 *
|
||||
|
@ -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 {
|
||||
|
@ -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___ */
|
||||
|
@ -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);
|
||||
|
@ -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
671
library/gsecret-session.c
Normal 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;
|
||||
}
|
@ -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 *
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = \
|
||||
|
@ -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
|
||||
|
||||
|
339
library/tests/test-collection.c
Normal file
339
library/tests/test-collection.c
Normal 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
534
library/tests/test-item.c
Normal 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
210
library/tests/test-value.c
Normal 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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user