[libsecret] When storing a secret, create default keyring if necessary



commit afc1d656791c938796894e7ef458a5d60875fc50
Author: Stef Walter <stefw gnome org>
Date:   Wed Nov 14 10:30:48 2012 +0100

    When storing a secret, create default keyring if necessary
    
     * If the default keyring does not exist when storing a secret
       try and create it.
     * We handle both secrets that correctly return NoSuchObject
       and ones that just return the silly DBus UnknownMethod error.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=688165

 libsecret/secret-collection.c         |    8 ++--
 libsecret/secret-methods.c            |   63 ++++++++++++++++++++++++++++++--
 libsecret/secret-private.h            |    4 ++
 libsecret/tests/mock-service-empty.py |   17 +++++++++
 libsecret/tests/test-methods.c        |   50 ++++++++++++++++++++++++++
 5 files changed, 134 insertions(+), 8 deletions(-)
---
diff --git a/libsecret/secret-collection.c b/libsecret/secret-collection.c
index 585f2af..24942b7 100644
--- a/libsecret/secret-collection.c
+++ b/libsecret/secret-collection.c
@@ -1042,8 +1042,8 @@ on_create_service (GObject *source,
 	g_object_unref (async);
 }
 
-static GHashTable *
-collection_properties_new (const gchar *label)
+GHashTable *
+_secret_collection_properties_new (const gchar *label)
 {
 	GHashTable *properties;
 	GVariant *value;
@@ -1104,7 +1104,7 @@ secret_collection_create (SecretService *service,
 	                                 secret_collection_create);
 	closure = g_slice_new0 (CreateClosure);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	closure->properties = collection_properties_new (label);
+	closure->properties = _secret_collection_properties_new (label);
 	closure->alias = g_strdup (alias);
 	closure->flags = flags;
 	g_simple_async_result_set_op_res_gpointer (res, closure, create_closure_free);
@@ -1208,7 +1208,7 @@ secret_collection_create_sync (SecretService *service,
 		g_object_ref (service);
 	}
 
-	properties = collection_properties_new (label);
+	properties = _secret_collection_properties_new (label);
 
 	path = secret_service_create_collection_dbus_path_sync (service, properties, alias,
 	                                                        flags, cancellable, error);
diff --git a/libsecret/secret-methods.c b/libsecret/secret-methods.c
index b768857..9dfaa7e 100644
--- a/libsecret/secret-methods.c
+++ b/libsecret/secret-methods.c
@@ -955,6 +955,7 @@ typedef struct {
 	gchar *collection_path;
 	SecretValue *value;
 	GHashTable *properties;
+	gboolean created_collection;
 } StoreClosure;
 
 static void
@@ -972,18 +973,72 @@ store_closure_free (gpointer data)
 static void
 on_store_create (GObject *source,
                  GAsyncResult *result,
-                 gpointer user_data)
+                 gpointer user_data);
+
+static void
+on_store_keyring (GObject *source,
+                  GAsyncResult *result,
+                  gpointer user_data)
 {
 	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
+	SecretService *service = SECRET_SERVICE (source);
 	GError *error = NULL;
 	gchar *path;
 
-	path = secret_service_create_item_dbus_path_finish (SECRET_SERVICE (source), result, &error);
-	if (error != NULL)
+	path = secret_service_create_collection_dbus_path_finish (service, result, &error);
+	if (error == NULL) {
+		store->created_collection = TRUE;
+		secret_service_create_item_dbus_path (service, store->collection_path,
+		                                      store->properties, store->value,
+		                                      SECRET_ITEM_CREATE_REPLACE, store->cancellable,
+		                                      on_store_create, g_object_ref (async));
+	} else {
 		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
 	g_free (path);
+}
 
-	g_simple_async_result_complete (async);
+static void
+on_store_create (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
+	SecretService *service = SECRET_SERVICE (source);
+	GError *error = NULL;
+	GHashTable *properties;
+	gchar *path;
+
+	path = secret_service_create_item_dbus_path_finish (service, result, &error);
+
+	/*
+	 * This happens when the collection doesn't exist. If the collection is
+	 * the default alias, we should try and create it
+	 */
+
+	if (!store->created_collection &&
+	    (g_error_matches (error, SECRET_ERROR, SECRET_ERROR_NO_SUCH_OBJECT) ||
+	     g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) &&
+	    g_strcmp0 (store->collection_path, SECRET_ALIAS_PREFIX "default") == 0) {
+		properties = _secret_collection_properties_new ("Default keyring");
+		secret_service_create_collection_dbus_path (service, properties, "default",
+		                                            SECRET_COLLECTION_CREATE_NONE, store->cancellable,
+		                                            on_store_keyring, g_object_ref (async));
+		g_hash_table_unref (properties);
+		g_error_free (error);
+
+	} else {
+		if (error != NULL)
+			g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_free (path);
 	g_object_unref (async);
 }
 
diff --git a/libsecret/secret-private.h b/libsecret/secret-private.h
index 74c9297..5e05032 100644
--- a/libsecret/secret-private.h
+++ b/libsecret/secret-private.h
@@ -31,6 +31,8 @@ typedef struct {
 
 typedef struct _SecretSession SecretSession;
 
+#define              SECRET_ALIAS_PREFIX                      "/org/freedesktop/secrets/aliases/"
+
 #define              SECRET_SERVICE_PATH                      "/org/freedesktop/secrets"
 
 #define              SECRET_SERVICE_BUS_NAME                  "org.freedesktop.secrets"
@@ -166,6 +168,8 @@ gint                 _secret_service_xlock_paths_finish       (SecretService *se
                                                                gchar ***xlocked,
                                                                GError **error);
 
+GHashTable *         _secret_collection_properties_new        (const gchar *label);
+
 SecretItem *         _secret_collection_find_item_instance    (SecretCollection *self,
                                                                const gchar *item_path);
 
diff --git a/libsecret/tests/mock-service-empty.py b/libsecret/tests/mock-service-empty.py
new file mode 100644
index 0000000..27bd3d4
--- /dev/null
+++ b/libsecret/tests/mock-service-empty.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+#
+# 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.1 of the licence or (at
+# your option) any later version.
+#
+# See the included COPYING file for more information.
+#
+
+import mock
+
+service = mock.SecretService()
+service.listen()
diff --git a/libsecret/tests/test-methods.c b/libsecret/tests/test-methods.c
index ecaf6f5..fe77134 100644
--- a/libsecret/tests/test-methods.c
+++ b/libsecret/tests/test-methods.c
@@ -866,6 +866,55 @@ test_store_async (Test *test,
 }
 
 static void
+test_store_no_default (Test *test,
+                       gconstpointer used)
+{
+	SecretValue *value = secret_value_new ("apassword", -1, "text/plain");
+	GHashTable *attributes;
+	GError *error = NULL;
+	gchar **paths;
+	gboolean ret;
+	gsize length;
+
+	attributes = secret_attributes_build (&MOCK_SCHEMA,
+	                                      "even", FALSE,
+	                                      "string", "seventeen",
+	                                      "number", 17,
+	                                      NULL);
+
+	ret = secret_service_store_sync (test->service, &MOCK_SCHEMA, attributes, SECRET_COLLECTION_DEFAULT,
+	                                 "New Item Label", value, NULL, &error);
+	g_assert_no_error (error);
+	secret_value_unref (value);
+	g_hash_table_unref (attributes);
+
+	attributes = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (attributes, "even", "false");
+	g_hash_table_insert (attributes, "string", "seventeen");
+	g_hash_table_insert (attributes, "number", "17");
+
+	ret = secret_service_search_for_dbus_paths_sync (test->service, &MOCK_SCHEMA, attributes,
+	                                                 NULL, &paths, NULL, &error);
+	g_hash_table_unref (attributes);
+	g_assert (ret == TRUE);
+
+	g_assert (paths != NULL);
+	g_assert (paths[0] != NULL);
+	g_assert (paths[1] == NULL);
+
+	value = secret_service_get_secret_for_dbus_path_sync (test->service, paths[0],
+	                                                      NULL, &error);
+	g_assert_no_error (error);
+
+	g_assert (value != NULL);
+	g_assert_cmpstr (secret_value_get (value, &length), ==, "apassword");
+	g_assert_cmpuint (length, ==, 9);
+
+	secret_value_unref (value);
+	g_strfreev (paths);
+}
+
+static void
 test_set_alias_sync (Test *test,
                      gconstpointer used)
 {
@@ -941,6 +990,7 @@ main (int argc, char **argv)
 	g_test_add ("/service/store-sync", Test, "mock-service-normal.py", setup, test_store_sync, teardown);
 	g_test_add ("/service/store-async", Test, "mock-service-normal.py", setup, test_store_async, teardown);
 	g_test_add ("/service/store-replace", Test, "mock-service-normal.py", setup, test_store_replace, teardown);
+	g_test_add ("/service/store-no-default", Test, "mock-service-empty.py", setup, test_store_no_default, teardown);
 
 	g_test_add ("/service/set-alias-sync", Test, "mock-service-normal.py", setup, test_set_alias_sync, teardown);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]