summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2012-03-11 09:06:40 +0100
committerStef Walter <stefw@gnome.org>2012-03-11 09:08:49 +0100
commit60f6e8e770045160d39d8c469e7e05d88ba50780 (patch)
tree9cccb79c5edba5634d6167d84c3a8922d5c27313
parent4f323b2e6785b188651b2a42d9200fa057a64276 (diff)
downloadlibsecret-60f6e8e770045160d39d8c469e7e05d88ba50780.tar.gz
Tons of fixes for introspectable usage
* Schemas can also be created dynamically * Correct introspection types for hash tables passed as args * Validate argument hash tables * Add some predefined schemas * Allow allocation of pageable passwords from lookup functions
-rw-r--r--docs/reference/libsecret/libsecret-sections.txt18
-rw-r--r--library/Makefile.am2
-rw-r--r--library/secret-item.c8
-rw-r--r--library/secret-methods.c46
-rw-r--r--library/secret-password.c270
-rw-r--r--library/secret-password.h14
-rw-r--r--library/secret-private.h7
-rw-r--r--library/secret-schema.c276
-rw-r--r--library/secret-schema.h80
-rw-r--r--library/secret-service.h1
-rw-r--r--library/secret-types.h26
-rw-r--r--library/secret-util.c102
-rw-r--r--library/secret-value.c32
-rw-r--r--library/secret.h1
-rw-r--r--library/tests/Makefile.am36
-rw-r--r--library/tests/test-methods.c14
-rw-r--r--library/tests/test-password.c31
17 files changed, 828 insertions, 136 deletions
diff --git a/docs/reference/libsecret/libsecret-sections.txt b/docs/reference/libsecret/libsecret-sections.txt
index ee86fcd..eaaf7d4 100644
--- a/docs/reference/libsecret/libsecret-sections.txt
+++ b/docs/reference/libsecret/libsecret-sections.txt
@@ -86,8 +86,6 @@ secret_error_get_type
<SECTION>
<FILE>secret-password</FILE>
-SecretSchema
-SecretSchemaType
secret_password_store
secret_password_storev
secret_password_store_finish
@@ -104,9 +102,21 @@ secret_password_remove_finish
secret_password_remove_sync
secret_password_removev_sync
secret_password_free
+</SECTION>
+
+<SECTION>
+<FILE>secret-schema</FILE>
+SecretSchema
+SecretSchemaAttribute
+SecretAttributeType
+secret_schema_new
+secret_schema_ref
+secret_schema_unref
<SUBSECTION Standard>
-SECRET_TYPE_SCHEMA_TYPE
-secret_schema_type_get_type
+SECRET_TYPE_SCHEMA
+secret_schema_get_type
+SECRET_TYPE_ATTRIBUTE_TYPE
+secret_attribute_type_get_type
</SECTION>
<SECTION>
diff --git a/library/Makefile.am b/library/Makefile.am
index 952daa5..0c8b8bc 100644
--- a/library/Makefile.am
+++ b/library/Makefile.am
@@ -26,6 +26,7 @@ HEADER_FILES = \
secret-item.h \
secret-password.h \
secret-prompt.h \
+ secret-schema.h \
secret-service.h \
secret-types.h \
secret-value.h \
@@ -47,6 +48,7 @@ PUBLIC_FILES = \
secret-methods.c \
secret-password.h secret-password.c \
secret-prompt.h secret-prompt.c \
+ secret-schema.h secret-schema.c \
secret-service.h secret-service.c \
secret-types.h \
secret-value.h secret-value.c \
diff --git a/library/secret-item.c b/library/secret-item.c
index ee4fa11..3ef790c 100644
--- a/library/secret-item.c
+++ b/library/secret-item.c
@@ -676,7 +676,7 @@ item_properties_new (const gchar *schema_name,
* @collection: a secret collection to create this item in
* @schema_name: schema name for the new item
* @label: label for the new item
- * @attributes: attributes for the new item
+ * @attributes: (element-type utf8 utf8): attributes for the new item
* @value: secret value for the new item
* @replace: whether to replace an existing item with the same attributes
* @cancellable: optional cancellation object
@@ -774,7 +774,7 @@ secret_item_create_finish (GAsyncResult *result,
* @collection: a secret collection to create this item in
* @schema_name: schema name for the new item
* @label: label for the new item
- * @attributes: attributes for the new item
+ * @attributes: (element-type utf8 utf8): attributes for the new item
* @value: secret value for the new item
* @replace: whether to replace an existing item with the same attributes
* @cancellable: optional cancellation object
@@ -1369,7 +1369,7 @@ secret_item_get_attributes (SecretItem *self)
/**
* secret_item_set_attributes:
* @self: an item
- * @attributes: a new set of attributes
+ * @attributes: (element-type utf8 utf8): a new set of attributes
* @cancellable: optional cancellation object
* @callback: called when the asynchronous operation completes
* @user_data: data to pass to the callback
@@ -1423,7 +1423,7 @@ secret_item_set_attributes_finish (SecretItem *self,
/**
* secret_item_set_attributes_sync:
* @self: an item
- * @attributes: a new set of attributes
+ * @attributes: (element-type utf8 utf8): a new set of attributes
* @cancellable: optional cancellation object
* @error: location to place error on failure
*
diff --git a/library/secret-methods.c b/library/secret-methods.c
index 1f057e3..42a8f60 100644
--- a/library/secret-methods.c
+++ b/library/secret-methods.c
@@ -44,7 +44,7 @@ on_search_items_complete (GObject *source,
/**
* secret_service_search_for_paths:
* @self: the secret service
- * @attributes: search for items matching these attributes
+ * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to pass to the callback
@@ -133,7 +133,7 @@ secret_service_search_for_paths_finish (SecretService *self,
/**
* secret_service_search_for_paths_sync:
* @self: the secret service
- * @attributes: search for items matching these attributes
+ * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @cancellable: optional cancellation object
* @unlocked: (out) (transfer full) (array zero-terminated=1) (allow-none):
* location to place an array of dbus object paths for matching
@@ -292,7 +292,7 @@ on_search_paths (GObject *source,
/**
* secret_service_search:
* @self: the secret service
- * @attributes: search for items matching these attributes
+ * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to pass to the callback
@@ -422,7 +422,7 @@ service_load_items_sync (SecretService *self,
/**
* secret_service_search_sync:
* @self: the secret service
- * @attributes: search for items matching these attributes
+ * @attributes: (element-type utf8 utf8): search for items matching these attributes
* @cancellable: optional cancellation object
* @unlocked: (out) (transfer full) (element-type Secret.Item) (allow-none):
* location to place a list of matching items which were not locked.
@@ -1713,7 +1713,7 @@ secret_service_store (SecretService *self,
* secret_service_storev:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @collection_path: the dbus path to the collection where to store the secret
* @label: label for the secret
* @value: the secret value
@@ -1752,6 +1752,10 @@ secret_service_storev (SecretService *self,
g_return_if_fail (value != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
(GDestroyNotify)g_variant_unref);
@@ -1760,7 +1764,7 @@ secret_service_storev (SecretService *self,
SECRET_ITEM_INTERFACE ".Label",
g_variant_ref_sink (propval));
- propval = g_variant_new_string (schema->schema_name);
+ propval = g_variant_new_string (schema->identifier);
g_hash_table_insert (properties,
SECRET_ITEM_INTERFACE ".Schema",
g_variant_ref_sink (propval));
@@ -1866,7 +1870,7 @@ secret_service_store_sync (SecretService *self,
* secret_service_storev_sync:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @collection_path: the dbus path to the collection where to store the secret
* @label: label for the secret
* @value: the secret value
@@ -1907,6 +1911,10 @@ secret_service_storev_sync (SecretService *self,
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
@@ -2073,7 +2081,7 @@ on_lookup_searched (GObject *source,
* secret_service_lookupv:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to be passed to the callback
@@ -2100,6 +2108,10 @@ secret_service_lookupv (SecretService *self,
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
secret_service_lookupv);
closure = g_slice_new0 (LookupClosure);
@@ -2202,7 +2214,7 @@ secret_service_lookup_sync (SecretService *self,
* secret_service_lookupv_sync:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
@@ -2231,6 +2243,10 @@ secret_service_lookupv_sync (SecretService *self,
g_return_val_if_fail (attributes != NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return NULL;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
@@ -2570,7 +2586,7 @@ secret_service_remove (SecretService *self,
* secret_service_removev:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to be passed to the callback
@@ -2599,6 +2615,10 @@ secret_service_removev (SecretService *self,
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
secret_service_remove);
closure = g_slice_new0 (DeleteClosure);
@@ -2696,7 +2716,7 @@ secret_service_remove_sync (SecretService *self,
* secret_service_removev_sync:
* @self: the secret service
* @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
@@ -2726,6 +2746,10 @@ secret_service_removev_sync (SecretService *self,
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
diff --git a/library/secret-password.c b/library/secret-password.c
index 0996d66..4915214 100644
--- a/library/secret-password.c
+++ b/library/secret-password.c
@@ -37,41 +37,6 @@
* values. Include a %NULL to terminate the list of attributes.
*/
-/**
- * SecretSchema:
- * @schema_name: the dotted name of the schema
- * @attributes: the attribute names and types of those attributes
- *
- * Represents a set of attributes that are stored with an item. These schemas
- * are used for interoperability between various services storing the same types
- * of items.
- *
- * Each schema has a name like "org.gnome.keyring.NetworkPassword", and defines
- * a set of attributes, and types (string, integer, boolean) for those attributes.
- *
- * Attributes are stored as strings in the Secret Service, and the attribute
- * types simply define standard ways to store integer and boolean values as strings.
- */
-
-/**
- * SecretSchemaAttribute:
- * @name: name of the attribute
- * @type: the type of the attribute
- *
- * An attribute in a #SecretSchema.
- */
-
-/**
- * SecretSchemaType:
- * @SECRET_ATTRIBUTE_BOOLEAN: a boolean attribute, stored as 'true' or 'false'
- * @SECRET_ATTRIBUTE_INTEGER: an integer attribute, stored as a decimal
- * @SECRET_ATTRIBUTE_STRING: a utf-8 string attribute
- *
- * The type of an attribute in a #SecretSchema. Attributes are stored as strings
- * in the Secret Service, and the attribute types simply define standard ways
- * to store integer and boolean values as strings.
- */
-
typedef struct {
const SecretSchema *schema;
GHashTable *attributes;
@@ -196,7 +161,7 @@ secret_password_store (const SecretSchema *schema,
/**
* secret_password_storev:
* @schema: the schema for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @collection_path: the dbus path to the collection where to store the secret
* @label: label for the secret
* @password: the null-terminated password to store
@@ -212,6 +177,8 @@ secret_password_store (const SecretSchema *schema,
* the item will be updated with these new values.
*
* This method will return immediately and complete asynchronously.
+ *
+ * Rename to: secret_password_store
*/
void
secret_password_storev (const SecretSchema *schema,
@@ -233,6 +200,10 @@ secret_password_storev (const SecretSchema *schema,
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
res = g_simple_async_result_new (NULL, callback, user_data,
secret_password_storev);
closure = g_slice_new0 (StoreClosure);
@@ -240,7 +211,7 @@ secret_password_storev (const SecretSchema *schema,
closure->collection_path = g_strdup (collection_path);
closure->label = g_strdup (label);
closure->value = secret_value_new (password, -1, "text/plain");
- closure->attributes = g_hash_table_ref (attributes);
+ closure->attributes = _secret_util_attributes_copy (attributes);
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free);
@@ -337,7 +308,7 @@ secret_password_store_sync (const SecretSchema *schema,
/**
* secret_password_storev_sync:
* @schema: the schema for attributes
- * @attributes: the attribute keys and values
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @collection_path: the dbus path to the collection where to store the secret
* @label: label for the secret
* @password: the null-terminated password to store
@@ -355,6 +326,8 @@ secret_password_store_sync (const SecretSchema *schema,
* threads.
*
* Returns: whether the storage was successful or not
+ *
+ * Rename to: secret_password_store_sync
*/
gboolean
secret_password_storev_sync (const SecretSchema *schema,
@@ -376,6 +349,10 @@ secret_password_storev_sync (const SecretSchema *schema,
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
@@ -411,7 +388,7 @@ lookup_closure_free (gpointer data)
}
/**
- * secret_password_lookup:
+ * secret_password_lookup: (skip)
* @schema: the schema to for attributes
* @cancellable: optional cancellation object
* @callback: called when the operation completes
@@ -498,8 +475,8 @@ on_lookup_connected (GObject *source,
/**
* secret_password_lookupv:
- * @schema: the schema for attributes
- * @attributes: the attribute keys and values
+ * @schema: (allow-none): the schema for attributes
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to be passed to the callback
@@ -511,6 +488,8 @@ on_lookup_connected (GObject *source,
* If no secret is found then %NULL is returned.
*
* This method will return immediately and complete asynchronously.
+ *
+ * Rename to: secret_password_lookup
*/
void
secret_password_lookupv (const SecretSchema *schema,
@@ -522,16 +501,19 @@ secret_password_lookupv (const SecretSchema *schema,
GSimpleAsyncResult *res;
LookupClosure *closure;
- g_return_if_fail (schema != NULL);
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
res = g_simple_async_result_new (NULL, callback, user_data,
secret_password_lookupv);
closure = g_slice_new0 (LookupClosure);
closure->schema = schema;
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
- closure->attributes = g_hash_table_ref (attributes);
+ closure->attributes = _secret_util_attributes_copy (attributes);
g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free);
secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
@@ -541,6 +523,43 @@ secret_password_lookupv (const SecretSchema *schema,
}
/**
+ * secret_password_lookup_nonpageable_finish: (skip)
+ * @result: the asynchronous result passed to the callback
+ * @error: location to place an error on failure
+ *
+ * Finish an asynchronous operation to lookup a password in the secret service.
+ *
+ * Returns: (transfer full): a new password string stored in nonpageable memory
+ * which must be freed with secret_password_free() when done
+ */
+gchar *
+secret_password_lookup_nonpageable_finish (GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *res;
+ LookupClosure *closure;
+ const gchar *content_type;
+ gchar *password = NULL;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+ secret_password_lookupv), NULL);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return NULL;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ content_type = secret_value_get_content_type (closure->value);
+ if (content_type && g_str_equal (content_type, "text/plain")) {
+ password = _secret_value_unref_to_password (closure->value);
+ closure->value = NULL;
+ }
+
+ return password;
+}
+
+/**
* secret_password_lookup_finish:
* @result: the asynchronous result passed to the callback
* @error: location to place an error on failure
@@ -548,7 +567,7 @@ secret_password_lookupv (const SecretSchema *schema,
* Finish an asynchronous operation to lookup a password in the secret service.
*
* Returns: (transfer full): a new password string which should be freed with
- * secret_password_free() when done
+ * secret_password_free() or may be freed with g_free() when done
*/
gchar *
secret_password_lookup_finish (GAsyncResult *result,
@@ -557,7 +576,7 @@ secret_password_lookup_finish (GAsyncResult *result,
GSimpleAsyncResult *res;
LookupClosure *closure;
const gchar *content_type;
- gchar *password = NULL;
+ gchar *string = NULL;
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
@@ -570,15 +589,15 @@ secret_password_lookup_finish (GAsyncResult *result,
closure = g_simple_async_result_get_op_res_gpointer (res);
content_type = secret_value_get_content_type (closure->value);
if (content_type && g_str_equal (content_type, "text/plain")) {
- password = _secret_value_unref_to_password (closure->value);
+ string = _secret_value_unref_to_string (closure->value);
closure->value = NULL;
}
- return password;
+ return string;
}
/**
- * secret_password_lookup_sync:
+ * secret_password_lookup_sync: (skip)
* @schema: the schema to for attributes
* @cancellable: optional cancellation object
* @error: location to place an error on failure
@@ -597,7 +616,7 @@ secret_password_lookup_finish (GAsyncResult *result,
* threads.
*
* Returns: (transfer full): a new password string which should be freed with
- * secret_password_free() when done
+ * secret_password_free() or may be freed with g_free() when done
*/
gchar *
secret_password_lookup_sync (const SecretSchema *schema,
@@ -626,9 +645,109 @@ secret_password_lookup_sync (const SecretSchema *schema,
}
/**
+ * secret_password_lookup_nonpageable_sync: (skip)
+ * @schema: the schema to for attributes
+ * @cancellable: optional cancellation object
+ * @error: location to place an error on failure
+ * @...: the attribute keys and values, terminated with %NULL
+ *
+ * Lookup a password in the secret service.
+ *
+ * The variable argument list should contain pairs of a) The attribute name as
+ * a null-terminated string, followed by b) attribute value, either a character
+ * string, an int number, or a gboolean value, as defined in the password
+ * @schema. The list of attribtues should be terminated with a %NULL.
+ *
+ * If no secret is found then %NULL is returned.
+ *
+ * This method may block indefinitely and should not be used in user interface
+ * threads.
+ *
+ * Returns: (transfer full): a new password string stored in nonpageable memory
+ * which must be freed with secret_password_free() when done
+ */
+gchar *
+secret_password_lookup_nonpageable_sync (const SecretSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...)
+{
+ GHashTable *attributes;
+ gchar *password;
+ va_list va;
+
+ g_return_val_if_fail (schema != NULL, NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ va_start (va, error);
+ attributes = _secret_util_attributes_for_varargs (schema, va);
+ va_end (va);
+
+ password = secret_password_lookupv_nonpageable_sync (schema, attributes,
+ cancellable, error);
+
+ g_hash_table_unref (attributes);
+
+ return password;
+}
+
+/**
+ * secret_password_lookupv_nonpageable_sync: (skip)
+ * @schema: (allow-none): the schema for attributes
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
+ * @cancellable: optional cancellation object
+ * @error: location to place an error on failure
+ *
+ * Lookup a password in the secret service.
+ *
+ * The @attributes should be a set of key and value string pairs.
+ *
+ * If no secret is found then %NULL is returned.
+ *
+ * This method may block indefinitely and should not be used in user interface
+ * threads.
+ *
+ * Returns: (transfer full): a new password string stored in non pageable memory
+ * which should be freed with secret_password_free() when done
+ */
+gchar *
+secret_password_lookupv_nonpageable_sync (const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SecretSync *sync;
+ gchar *password;
+
+ g_return_val_if_fail (attributes != NULL, NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
+ sync = _secret_sync_new ();
+ g_main_context_push_thread_default (sync->context);
+
+ secret_password_lookupv (schema, attributes, cancellable,
+ _secret_sync_on_result, sync);
+
+ g_main_loop_run (sync->loop);
+
+ password = secret_password_lookup_nonpageable_finish (sync->result, error);
+
+ g_main_context_pop_thread_default (sync->context);
+ _secret_sync_free (sync);
+
+ return password;
+}
+
+/**
* secret_password_lookupv_sync:
- * @schema: the schema for attributes
- * @attributes: the attribute keys and values
+ * @schema: (allow-none): the schema for attributes
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
@@ -642,7 +761,9 @@ secret_password_lookup_sync (const SecretSchema *schema,
* threads.
*
* Returns: (transfer full): a new password string which should be freed with
- * secret_password_free() when done
+ * secret_password_free() or may be freed with g_free() when done
+ *
+ * Rename to: secret_password_lookup_sync
*/
gchar *
secret_password_lookupv_sync (const SecretSchema *schema,
@@ -651,13 +772,16 @@ secret_password_lookupv_sync (const SecretSchema *schema,
GError **error)
{
SecretSync *sync;
- gchar *password;
+ gchar *string;
- g_return_val_if_fail (schema != NULL, NULL);
g_return_val_if_fail (attributes != NULL, NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
@@ -666,12 +790,12 @@ secret_password_lookupv_sync (const SecretSchema *schema,
g_main_loop_run (sync->loop);
- password = secret_password_lookup_finish (sync->result, error);
+ string = secret_password_lookup_finish (sync->result, error);
g_main_context_pop_thread_default (sync->context);
_secret_sync_free (sync);
- return password;
+ return string;
}
typedef struct {
@@ -777,8 +901,8 @@ on_delete_connect (GObject *source,
/**
* secret_password_removev:
- * @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @schema: (allow-none): the schema to for attributes
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @callback: called when the operation completes
* @user_data: data to be passed to the callback
@@ -790,6 +914,8 @@ on_delete_connect (GObject *source,
* If multiple items match the attributes, then only one will be deleted.
*
* This method will return immediately and complete asynchronously.
+ *
+ * Rename to: secret_password_remove
*/
void
secret_password_removev (const SecretSchema *schema,
@@ -801,15 +927,18 @@ secret_password_removev (const SecretSchema *schema,
GSimpleAsyncResult *res;
DeleteClosure *closure;
- g_return_if_fail (schema != NULL);
g_return_if_fail (attributes != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return;
+
res = g_simple_async_result_new (NULL, callback, user_data,
secret_password_removev);
closure = g_slice_new0 (DeleteClosure);
closure->schema = schema;
- closure->attributes = g_hash_table_ref (attributes);
+ closure->attributes = _secret_util_attributes_copy (attributes);
closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
@@ -897,8 +1026,8 @@ secret_password_remove_sync (const SecretSchema* schema,
/**
* secret_password_removev_sync:
- * @schema: the schema to for attributes
- * @attributes: the attribute keys and values
+ * @schema: (allow-none): the schema to for attributes
+ * @attributes: (element-type utf8 utf8): the attribute keys and values
* @cancellable: optional cancellation object
* @error: location to place an error on failure
*
@@ -912,6 +1041,8 @@ secret_password_remove_sync (const SecretSchema* schema,
* threads.
*
* Returns: whether the removal was successful or not
+ *
+ * Rename to: secret_password_remove_sync
*/
gboolean
secret_password_removev_sync (const SecretSchema *schema,
@@ -922,11 +1053,14 @@ secret_password_removev_sync (const SecretSchema *schema,
SecretSync *sync;
gboolean result;
- g_return_val_if_fail (schema != NULL, FALSE);
g_return_val_if_fail (attributes != NULL, FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* Warnings raised already */
+ if (!_secret_util_attributes_validate (schema, attributes))
+ return FALSE;
+
sync = _secret_sync_new ();
g_main_context_push_thread_default (sync->context);
@@ -944,11 +1078,15 @@ secret_password_removev_sync (const SecretSchema *schema,
}
/**
- * secret_password_free:
+ * secret_password_free: (skip)
* @password: (allow-none): password to free
*
- * Free a password returned by secret_password_lookup_finish(),
- * secret_password_lookup_sync() or secret_password_lookupv_sync().
+ * Clear the memory used by a password, and then free it.
+ *
+ * This function must be used to free nonpageable memory returned by
+ * secret_password_lookup_nonpageable_finish(),
+ * secret_password_lookup_nonpageable_sync() or
+ * secret_password_lookupv_nonpageable_sync().
*/
void
secret_password_free (gchar *password)
diff --git a/library/secret-password.h b/library/secret-password.h
index 1292a9d..56ed05b 100644
--- a/library/secret-password.h
+++ b/library/secret-password.h
@@ -21,6 +21,7 @@
G_BEGIN_DECLS
+#include "secret-schema.h"
#include "secret-types.h"
void secret_password_store (const SecretSchema *schema,
@@ -75,16 +76,29 @@ void secret_password_lookupv (const SecretSchema *sche
gchar * secret_password_lookup_finish (GAsyncResult *result,
GError **error);
+gchar * secret_password_lookup_nonpageable_finish (GAsyncResult *result,
+ GError **error);
+
gchar * secret_password_lookup_sync (const SecretSchema *schema,
GCancellable *cancellable,
GError **error,
...) G_GNUC_NULL_TERMINATED;
+gchar * secret_password_lookup_nonpageable_sync (const SecretSchema *schema,
+ GCancellable *cancellable,
+ GError **error,
+ ...);
+
gchar * secret_password_lookupv_sync (const SecretSchema *schema,
GHashTable *attributes,
GCancellable *cancellable,
GError **error);
+gchar * secret_password_lookupv_nonpageable_sync (const SecretSchema *schema,
+ GHashTable *attributes,
+ GCancellable *cancellable,
+ GError **error);
+
void secret_password_remove (const SecretSchema *schema,
GCancellable *cancellable,
GAsyncReadyCallback callback,
diff --git a/library/secret-private.h b/library/secret-private.h
index cc5779b..351ce94 100644
--- a/library/secret-private.h
+++ b/library/secret-private.h
@@ -65,6 +65,11 @@ GHashTable * _secret_util_attributes_for_variant (GVariant *variant
GHashTable * _secret_util_attributes_for_varargs (const SecretSchema *schema,
va_list va);
+GHashTable * _secret_util_attributes_copy (GHashTable *attributes);
+
+gboolean _secret_util_attributes_validate (const SecretSchema *schema,
+ GHashTable *attributes);
+
GVariant * _secret_util_variant_for_properties (GHashTable *properties);
void _secret_util_get_properties (GDBusProxy *proxy,
@@ -121,6 +126,8 @@ SecretItem * _secret_collection_find_item_instance (SecretCollection
gchar * _secret_value_unref_to_password (SecretValue *value);
+gchar * _secret_value_unref_to_string (SecretValue *value);
+
void _secret_session_free (gpointer data);
const gchar * _secret_session_get_algorithms (SecretSession *session);
diff --git a/library/secret-schema.c b/library/secret-schema.c
new file mode 100644
index 0000000..8fbf254
--- /dev/null
+++ b/library/secret-schema.c
@@ -0,0 +1,276 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2011 Collabora Ltd.
+ *
+ * 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 "secret-enum-types.h"
+#include "secret-password.h"
+#include "secret-private.h"
+#include "secret-value.h"
+
+#include <egg/egg-secure-memory.h>
+
+/**
+ * SECTION:secret-schema
+ * @title: SecretSchema
+ * @short_description: Schema for defining which attributes are on items
+ *
+ * Each password is associated with a set of attributes. Attribute values can
+ * be either strings, integers or booleans.
+ *
+ * The names and types of allowed attributes for a given password are defined
+ * with a schema. Certain schemas are predefined like %SECRET_SCHEMA_NETWORK.
+ *
+ * Additional schemas can be defined via the %SecretSchema structure like this:
+ *
+ * xxxx
+ */
+
+/**
+ * SecretSchema:
+ * @identifier: the dotted identifer of the schema
+ * @attributes: the attribute names and types of those attributes
+ *
+ * Represents a set of attributes that are stored with an item. These schemas
+ * are used for interoperability between various services storing the same types
+ * of items.
+ *
+ * Each schema has a identifier like "org.gnome.keyring.NetworkPassword", and defines
+ * a set of attributes, and types (string, integer, boolean) for those attributes.
+ *
+ * Attributes are stored as strings in the Secret Service, and the attribute
+ * types simply define standard ways to store integer and boolean values as strings.
+ */
+
+/**
+ * SecretSchemaAttribute:
+ * @name: name of the attribute
+ * @type: the type of the attribute
+ *
+ * An attribute in a #SecretSchema.
+ */
+
+/**
+ * SecretAttributeType:
+ * @SECRET_ATTRIBUTE_BOOLEAN: a boolean attribute, stored as 'true' or 'false'
+ * @SECRET_ATTRIBUTE_INTEGER: an integer attribute, stored as a decimal
+ * @SECRET_ATTRIBUTE_STRING: a utf-8 string attribute
+ *
+ * The type of an attribute in a #SecretSchema. Attributes are stored as strings
+ * in the Secret Service, and the attribute types simply define standard ways
+ * to store integer and boolean values as strings.
+ */
+
+static const SecretSchema network_schema = {
+ SECRET_SCHEMA_IDENTIFIER_NETWORK,
+ SECRET_SCHEMA_NONE,
+ {
+ { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "domain", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "object", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "port", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "NULL", 0 },
+ }
+};
+
+const SecretSchema * SECRET_SCHEMA_NETWORK = &network_schema;
+
+static const SecretSchema generic_schema = {
+ SECRET_SCHEMA_IDENTIFIER_GENERIC,
+ SECRET_SCHEMA_ALLOW_UNDEFINED,
+ {
+ { "NULL", 0 },
+ }
+};
+
+const SecretSchema * SECRET_SCHEMA_GENERIC = &generic_schema;
+
+static const SecretSchema note_schema = {
+ SECRET_SCHEMA_IDENTIFIER_NOTE,
+ SECRET_SCHEMA_ALLOW_UNDEFINED,
+ {
+ { "NULL", 0 },
+ }
+};
+
+const SecretSchema * SECRET_SCHEMA_NOTE = &note_schema;
+
+static SecretSchemaAttribute *
+schema_attribute_copy (SecretSchemaAttribute *attribute)
+{
+ SecretSchemaAttribute *copy;
+
+ copy = g_slice_new0 (SecretSchemaAttribute);
+ copy->name = g_strdup (attribute->name);
+ copy->type = attribute->type;
+
+ return copy;
+}
+
+static void
+schema_attribute_free (SecretSchemaAttribute *attribute)
+{
+ g_free ((gchar *)attribute->name);
+ g_slice_free (SecretSchemaAttribute, attribute);
+}
+
+G_DEFINE_BOXED_TYPE (SecretSchemaAttribute, secret_schema_attribute,
+ schema_attribute_copy, schema_attribute_free);
+
+/**
+ * secret_schema_new:
+ * @identifier: the dotted identifier of the schema
+ * @attributes: (element-type utf8 Secret.SchemaAttributeType): the attribute names and types of those attributes
+ *
+ * Using this function is not normally necessary from C code. This is useful
+ * for constructing #SecretSchema structures in bindings.
+ *
+ * A schema represents a set of attributes that are stored with an item. These
+ * schemas are used for interoperability between various services storing the
+ * same types of items.
+ *
+ * Each schema has an @identifier like "org.gnome.keyring.NetworkPassword", and
+ * defines a set of attributes names, and types (string, integer, boolean) for
+ * those attributes.
+ *
+ * Each key in the @attributes table should be a attribute name strings, and
+ * the values in the table should be integers from the #SecretAttributeType
+ * enumeration, representing the attribute type for each attribute name.
+ *
+ * Returns: (transfer full): the new schema, which should be unreferenced with
+ * secret_schema_unref() when done
+ */
+SecretSchema *
+secret_schema_new (const gchar *identifier,
+ SecretSchemaFlags flags,
+ GHashTable *attributes)
+{
+ SecretSchema *schema;
+ GHashTableIter iter;
+ GEnumClass *enumc;
+ gpointer value;
+ gpointer key;
+ gint type;
+ gint ind = 0;
+
+ g_return_val_if_fail (identifier != NULL, NULL);
+
+ schema = g_slice_new0 (SecretSchema);
+ schema->identifier = g_strdup (identifier);
+ schema->flags = flags;
+ schema->reserved = 1;
+
+ if (attributes) {
+ g_hash_table_iter_init (&iter, attributes);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+
+ if (ind >= G_N_ELEMENTS (schema->attributes)) {
+ g_warning ("too many attributes for schema, max %d",
+ (gint) G_N_ELEMENTS (schema->attributes));
+ break;
+ }
+
+ type = GPOINTER_TO_INT (value);
+
+ enumc = G_ENUM_CLASS (g_type_class_ref (SECRET_TYPE_SCHEMA_ATTRIBUTE_TYPE));
+ if (!g_enum_get_value (enumc, type)) {
+ g_warning ("invalid type for attribute %s", (gchar *)key);
+ type = -1;
+ }
+
+ g_type_class_unref (enumc);
+
+ if (type >= 0) {
+ schema->attributes[ind].name = g_strdup (key);
+ schema->attributes[ind].type = type;
+ }
+
+ ind++;
+ }
+ }
+
+ return schema;
+}
+
+/**
+ * secret_schema_ref:
+ * @schema: the schema to reference
+ *
+ * Adds a reference to the #SecretSchema.
+ *
+ * It is not normally necessary to call this function from C code, and is
+ * mainly present for the sake of bindings. If the @schema was statically
+ * allocated, then this function will copy the schema.
+ *
+ * Returns: (transfer full): the referenced schema, which should be later
+ * unreferenced with secret_schema_unref()
+ */
+SecretSchema *
+secret_schema_ref (SecretSchema *schema)
+{
+ SecretSchema *result;
+ gint i;
+
+ g_return_val_if_fail (schema != NULL, NULL);
+
+ /* If it's static, then copy it */
+ if (g_atomic_int_get (&schema->reserved) > 0) {
+ g_atomic_int_inc (&schema->reserved);
+ result = schema;
+ } else {
+ result = g_slice_new0 (SecretSchema);
+ result->reserved = 1;
+ result->identifier = g_strdup (schema->identifier);
+
+ for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
+ result->attributes[i].name = g_strdup (schema->attributes[i].name);
+ result->attributes[i].type = schema->attributes[i].type;
+ }
+ }
+
+ return result;
+}
+
+/**
+ * secret_schema_unref:
+ * @schema: the schema to reference
+ *
+ * Releases a reference to the #SecretSchema. If the last reference is
+ * released then the schema will be freed.
+ *
+ * It is not normally necessary to call this function from C code, and is
+ * mainly present for the sake of bindings. It is an error to call this for
+ * a @schema that was statically allocated.
+ */
+void
+secret_schema_unref (SecretSchema *schema)
+{
+ gint refs;
+ gint i;
+
+ g_return_if_fail (schema != NULL);
+
+ refs = g_atomic_int_add (&schema->reserved, -1);
+ if (refs < 0) {
+ g_warning ("should not unreference a static or invalid SecretSchema");
+
+ } else if (refs == 0) {
+ g_free ((gpointer)schema->identifier);
+ for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++)
+ g_free ((gpointer)schema->attributes[i].name);
+ g_slice_free (SecretSchema, schema);
+ }
+}
+
+G_DEFINE_BOXED_TYPE (SecretSchema, secret_schema, secret_schema_ref, secret_schema_unref);
diff --git a/library/secret-schema.h b/library/secret-schema.h
new file mode 100644
index 0000000..1473d69
--- /dev/null
+++ b/library/secret-schema.h
@@ -0,0 +1,80 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2011 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.
+ */
+
+#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION)
+#error "Only <secret/secret.h> can be included directly."
+#endif
+
+#ifndef __SECRET_SCHEMA_H__
+#define __SECRET_SCHEMA_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define SECRET_SCHEMA_IDENTIFIER_GENERIC "org.freedesktop.Secret.Generic"
+#define SECRET_SCHEMA_IDENTIFIER_NETWORK "org.gnome.keyring.NetworkPassword"
+#define SECRET_SCHEMA_IDENTIFIER_NOTE "org.gnome.keyring.Note"
+
+typedef enum {
+ SECRET_SCHEMA_ATTRIBUTE_STRING = 0,
+ SECRET_SCHEMA_ATTRIBUTE_INTEGER = 1,
+ SECRET_SCHEMA_ATTRIBUTE_BOOLEAN = 2,
+} SecretSchemaAttributeType;
+
+typedef struct {
+ const gchar* name;
+ SecretSchemaAttributeType type;
+} SecretSchemaAttribute;
+
+typedef enum {
+ SECRET_SCHEMA_NONE = 0,
+ SECRET_SCHEMA_ALLOW_UNDEFINED = 1 << 0,
+} SecretSchemaFlags;
+
+typedef struct {
+ const gchar *identifier;
+ SecretSchemaFlags flags;
+ SecretSchemaAttribute attributes[32];
+
+ /* <private> */
+ gint reserved;
+ gpointer reserved1;
+ gpointer reserved2;
+ gpointer reserved3;
+ gpointer reserved4;
+ gpointer reserved5;
+ gpointer reserved6;
+ gpointer reserved7;
+} SecretSchema;
+
+extern const SecretSchema * SECRET_SCHEMA_NETWORK;
+
+extern const SecretSchema * SECRET_SCHEMA_GENERIC;
+
+extern const SecretSchema * SECRET_SCHEMA_NOTE;
+
+GType secret_schema_get_type (void) G_GNUC_CONST;
+
+SecretSchema * secret_schema_new (const gchar *identifier,
+ SecretSchemaFlags flags,
+ GHashTable *attributes);
+
+SecretSchema * secret_schema_ref (SecretSchema *schema);
+
+void secret_schema_unref (SecretSchema *schema);
+
+GType secret_schema_attribute_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __SECRET_SCHEMA_H___ */
diff --git a/library/secret-service.h b/library/secret-service.h
index 5c12efd..32b0a8e 100644
--- a/library/secret-service.h
+++ b/library/secret-service.h
@@ -21,6 +21,7 @@
#include <gio/gio.h>
#include "secret-prompt.h"
+#include "secret-schema.h"
#include "secret-types.h"
#include "secret-value.h"
diff --git a/library/secret-types.h b/library/secret-types.h
index b13eb78..96d8637 100644
--- a/library/secret-types.h
+++ b/library/secret-types.h
@@ -29,32 +29,6 @@ typedef enum {
SECRET_ERROR_PROTOCOL = 1,
} SecretError;
-typedef enum {
- SECRET_ATTRIBUTE_BOOLEAN,
- SECRET_ATTRIBUTE_STRING,
- SECRET_ATTRIBUTE_INTEGER
-} SecretSchemaType;
-
-typedef struct {
- const gchar* name;
- SecretSchemaType type;
-} SecretSchemaAttribute;
-
-typedef struct {
- const gchar *schema_name;
- SecretSchemaAttribute attributes[32];
-
- /* <private> */
- gpointer reserved1;
- gpointer reserved2;
- gpointer reserved3;
- gpointer reserved4;
- gpointer reserved5;
- gpointer reserved6;
- gpointer reserved7;
- gpointer reserved8;
-} SecretSchema;
-
typedef struct _SecretCollection SecretCollection;
typedef struct _SecretItem SecretItem;
typedef struct _SecretPrompt SecretPrompt;
diff --git a/library/secret-util.c b/library/secret-util.c
index 1e80d75..a65b503 100644
--- a/library/secret-util.c
+++ b/library/secret-util.c
@@ -155,7 +155,7 @@ _secret_util_attributes_for_varargs (const SecretSchema *schema,
va_list args)
{
const gchar *attribute_name;
- SecretSchemaType type;
+ SecretSchemaAttributeType type;
GHashTable *attributes;
const gchar *string;
gboolean type_found;
@@ -189,11 +189,11 @@ _secret_util_attributes_for_varargs (const SecretSchema *schema,
}
switch (type) {
- case SECRET_ATTRIBUTE_BOOLEAN:
+ case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
boolean = va_arg (args, gboolean);
value = g_strdup (boolean ? "true" : "false");
break;
- case SECRET_ATTRIBUTE_STRING:
+ case SECRET_SCHEMA_ATTRIBUTE_STRING:
string = va_arg (args, gchar *);
if (!g_utf8_validate (string, -1, NULL)) {
g_warning ("The value for attribute '%s' was not a valid utf-8 string.", attribute_name);
@@ -202,7 +202,7 @@ _secret_util_attributes_for_varargs (const SecretSchema *schema,
}
value = g_strdup (string);
break;
- case SECRET_ATTRIBUTE_INTEGER:
+ case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
integer = va_arg (args, gint);
value = g_strdup_printf ("%d", integer);
break;
@@ -218,6 +218,100 @@ _secret_util_attributes_for_varargs (const SecretSchema *schema,
return attributes;
}
+gboolean
+_secret_util_attributes_validate (const SecretSchema *schema,
+ GHashTable *attributes)
+{
+ const SecretSchemaAttribute *attribute;
+ GHashTableIter iter;
+ gchar *key;
+ gchar *value;
+ gchar *end;
+ gint i;
+
+ /* If no schema, then assume attributes are valid */
+ if (schema == NULL)
+ return TRUE;
+
+ g_hash_table_iter_init (&iter, attributes);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value)) {
+
+ /* Find the attribute */
+ attribute = NULL;
+ for (i = 0; i < G_N_ELEMENTS (schema->attributes); i++) {
+ if (schema->attributes[i].name == NULL)
+ break;
+ if (g_str_equal (schema->attributes[i].name, key)) {
+ attribute = &schema->attributes[i];
+ break;
+ }
+ }
+
+ if (attribute == NULL) {
+ if (!(schema->flags & SECRET_SCHEMA_ALLOW_UNDEFINED)) {
+ g_warning ("invalid %s attribute in for %s schema",
+ key, schema->identifier);
+ return FALSE;
+ }
+
+ /* Undefined attribute allowed */
+ continue;
+ }
+
+ switch (attribute->type) {
+ case SECRET_SCHEMA_ATTRIBUTE_BOOLEAN:
+ if (!g_str_equal (value, "true") && !g_str_equal (value, "false")) {
+ g_warning ("invalid %s boolean value for %s schema: %s",
+ key, schema->identifier, value);
+ return FALSE;
+ }
+ break;
+ case SECRET_SCHEMA_ATTRIBUTE_INTEGER:
+ end = NULL;
+ g_ascii_strtoll (value, &end, 10);
+ if (!end || end[0] != '\0') {
+ g_warning ("invalid %s integer value for %s schema: %s",
+ key, schema->identifier, value);
+ return FALSE;
+ }
+ break;
+ case SECRET_SCHEMA_ATTRIBUTE_STRING:
+ if (!g_utf8_validate (value, -1, NULL)) {
+ g_warning ("invalid %s string value for %s schema: %s",
+ key, schema->identifier, value);
+ return FALSE;
+ }
+ break;
+ default:
+ g_warning ("invalid %s value type in %s schema",
+ key, schema->identifier);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+GHashTable *
+_secret_util_attributes_copy (GHashTable *attributes)
+{
+ GHashTableIter iter;
+ GHashTable *copy;
+ gchar *key;
+ gchar *value;
+
+ if (attributes == NULL)
+ return NULL;
+
+ copy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ g_hash_table_iter_init (&iter, attributes);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+ g_hash_table_insert (copy, g_strdup (key), g_strdup (value));
+
+ return copy;
+}
+
static void
process_get_all_reply (GDBusProxy *proxy,
GVariant *retval)
diff --git a/library/secret-value.c b/library/secret-value.c
index 87ec3ca..07220f1 100644
--- a/library/secret-value.c
+++ b/library/secret-value.c
@@ -248,3 +248,35 @@ _secret_value_unref_to_password (SecretValue *value)
return result;
}
+
+gchar *
+_secret_value_unref_to_string (SecretValue *value)
+{
+ SecretValue *val = value;
+ gchar *result;
+
+ g_return_val_if_fail (value != NULL, NULL);
+
+ if (val->content_type && !g_str_equal (val->content_type, "text/plain")) {
+ secret_value_unref (value);
+ return NULL;
+ }
+
+ if (g_atomic_int_dec_and_test (&val->refs)) {
+ if (val->destroy == g_free) {
+ result = val->secret;
+
+ } else {
+ result = g_strdup (val->secret);
+ if (val->destroy)
+ (val->destroy) (val->secret);
+ }
+ g_free (val->content_type);
+ g_slice_free (SecretValue, val);
+
+ } else {
+ result = g_strdup (val->secret);
+ }
+
+ return result;
+}
diff --git a/library/secret.h b/library/secret.h
index 3b6a47b..09ad77f 100644
--- a/library/secret.h
+++ b/library/secret.h
@@ -26,6 +26,7 @@
#include <secret/secret-item.h>
#include <secret/secret-password.h>
#include <secret/secret-prompt.h>
+#include <secret/secret-schema.h>
#include <secret/secret-service.h>
#include <secret/secret-value.h>
diff --git a/library/tests/Makefile.am b/library/tests/Makefile.am
index 83bd222..db8c0e3 100644
--- a/library/tests/Makefile.am
+++ b/library/tests/Makefile.am
@@ -16,6 +16,9 @@ libmock_service_la_SOURCES = \
libmock_service_la_CFLAGS = \
$(LIBGCRYPT_CFLAGS)
+libmock_service_la_LDFLAGS = \
+ -rpath /force/shared
+
libmock_service_la_LIBADD = \
$(top_builddir)/egg/libegg.la \
$(top_builddir)/library/libsecret-@SECRET_MAJOR@.la \
@@ -56,6 +59,39 @@ EXTRA_DIST = \
test: $(TEST_PROGS)
gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(TEST_PROGS)
+test-javascript:
+ LD_LIBRARY_PATH=$(builddir)/.libs GI_TYPELIB_PATH=$(builddir)/..:$(builddir) \
+ gjs test-lookup-password.js
+
+# ------------------------------------------------------------------
+# INTROSPECTION
+
+if HAVE_INTROSPECTION
+
+include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS = MockService-0.gir
+INTROSPECTION_SCANNER_ARGS = $(INTROSPECTION_FLAGS) --warn-all --add-include-path=$(srcdir) --add-include-path=.
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) --includedir=.
+
+MockService-0.gir: libmock_service.la
+
+MockService_0_gir_PACKAGES = gobject-2.0 gio-2.0
+MockService_0_gir_EXPORT_PACKAGES = mock-service-0
+MockService_0_gir_INCLUDES = GObject-2.0 Gio-2.0
+MockService_0_gir_LIBS = libmock_service.la
+MockService_0_gir_CFLAGS = -I$(top_srcdir) -I$(top_builddir)
+MockService_0_gir_FILES = $(libmock_service_la_SOURCES)
+MockService_0_gir_SCANNERFLAGS = --c-include "mock-service.h"
+
+noinst_DATA = \
+ $(INTROSPECTION_GIRS) \
+ $(INTROSPECTION_GIRS:.gir=.typelib)
+
+endif
+
+#--------------------------------------------------------------------
+
all-local: $(check_PROGRAMS)
check-local: test
diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c
index a04979b..8c256fc 100644
--- a/library/tests/test-methods.c
+++ b/library/tests/test-methods.c
@@ -29,19 +29,21 @@
static const SecretSchema DELETE_SCHEMA = {
"org.mock.schema.Delete",
+ SECRET_SCHEMA_NONE,
{
- { "number", SECRET_ATTRIBUTE_INTEGER },
- { "string", SECRET_ATTRIBUTE_STRING },
- { "even", SECRET_ATTRIBUTE_BOOLEAN },
+ { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "string", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN },
}
};
static const SecretSchema STORE_SCHEMA = {
"org.mock.type.Store",
+ SECRET_SCHEMA_NONE,
{
- { "number", SECRET_ATTRIBUTE_INTEGER },
- { "string", SECRET_ATTRIBUTE_STRING },
- { "even", SECRET_ATTRIBUTE_BOOLEAN },
+ { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "string", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN },
}
};
diff --git a/library/tests/test-password.c b/library/tests/test-password.c
index e562289..65ecca7 100644
--- a/library/tests/test-password.c
+++ b/library/tests/test-password.c
@@ -28,10 +28,11 @@
static const SecretSchema PASSWORD_SCHEMA = {
"org.mock.schema.Password",
+ SECRET_SCHEMA_NONE,
{
- { "number", SECRET_ATTRIBUTE_INTEGER },
- { "string", SECRET_ATTRIBUTE_STRING },
- { "even", SECRET_ATTRIBUTE_BOOLEAN },
+ { "number", SECRET_SCHEMA_ATTRIBUTE_INTEGER },
+ { "string", SECRET_SCHEMA_ATTRIBUTE_STRING },
+ { "even", SECRET_SCHEMA_ATTRIBUTE_BOOLEAN },
}
};
@@ -76,11 +77,11 @@ test_lookup_sync (Test *test,
gchar *password;
GError *error = NULL;
- password = secret_password_lookup_sync (&PASSWORD_SCHEMA, NULL, &error,
- "even", FALSE,
- "string", "one",
- "number", 1,
- NULL);
+ password = secret_password_lookup_nonpageable_sync (&PASSWORD_SCHEMA, NULL, &error,
+ "even", FALSE,
+ "string", "one",
+ "number", 1,
+ NULL);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, "111");
@@ -105,7 +106,7 @@ test_lookup_async (Test *test,
egg_test_wait ();
- password = secret_password_lookup_finish (result, &error);
+ password = secret_password_lookup_nonpageable_finish (result, &error);
g_assert_no_error (error);
g_object_unref (result);
@@ -132,9 +133,9 @@ test_store_sync (Test *test,
g_assert_no_error (error);
g_assert (ret == TRUE);
- password = secret_password_lookup_sync (&PASSWORD_SCHEMA, NULL, &error,
- "string", "twelve",
- NULL);
+ password = secret_password_lookup_nonpageable_sync (&PASSWORD_SCHEMA, NULL, &error,
+ "string", "twelve",
+ NULL);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, "the password");
@@ -167,9 +168,9 @@ test_store_async (Test *test,
g_assert (ret == TRUE);
g_object_unref (result);
- password = secret_password_lookup_sync (&PASSWORD_SCHEMA, NULL, &error,
- "string", "twelve",
- NULL);
+ password = secret_password_lookup_nonpageable_sync (&PASSWORD_SCHEMA, NULL, &error,
+ "string", "twelve",
+ NULL);
g_assert_no_error (error);
g_assert_cmpstr (password, ==, "the password");