[libsecret/wip/dueno/file] secret-file: New backend for storing secrets in file [ci skip]



commit 3805be8ff59606ea1b4d9e3811be32273ad07d88
Author: Daiki Ueno <dueno src gnome org>
Date:   Tue Aug 13 18:12:35 2019 +0200

    secret-file: New backend for storing secrets in file [ci skip]

 libsecret/Makefile.am        |   3 +
 libsecret/secret-file-item.c | 247 ++++++++++++++++++++
 libsecret/secret-file-item.h |  32 +++
 libsecret/secret-file.c      | 528 +++++++++++++++++++++++++++++++++++++++++++
 libsecret/secret-file.h      |  31 +++
 libsecret/secret-item.c      |   3 +-
 6 files changed, 843 insertions(+), 1 deletion(-)
---
diff --git a/libsecret/Makefile.am b/libsecret/Makefile.am
index 0e34ea3..2d70825 100644
--- a/libsecret/Makefile.am
+++ b/libsecret/Makefile.am
@@ -52,9 +52,12 @@ libsecret_PUBLIC = \
        libsecret/secret-types.h \
        libsecret/secret-value.h libsecret/secret-value.c \
        libsecret/secret-paths.h libsecret/secret-paths.c \
+       libsecret/secret-file.h libsecret/secret-file.c \
        $(NULL)
 
 libsecret_PRIVATE = \
+       libsecret/secret-file-item.h \
+       libsecret/secret-file-item.c \
        libsecret/secret-private.h \
        libsecret/secret-session.c \
        libsecret/secret-util.c \
diff --git a/libsecret/secret-file-item.c b/libsecret/secret-file-item.c
new file mode 100644
index 0000000..f6200a2
--- /dev/null
+++ b/libsecret/secret-file-item.c
@@ -0,0 +1,247 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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.
+ *
+ * Author: Daiki Ueno
+ */
+
+#include "config.h"
+
+#include "secret-file-item.h"
+
+struct _SecretFileItem
+{
+       GObject parent;
+       GHashTable *attributes;
+       gchar *label;
+       guint64 created;
+       guint64 modified;
+       SecretValue *value;
+};
+
+static void secret_file_item_retrievable_iface (SecretRetrievableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (SecretFileItem, secret_file_item, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_file_item_retrievable_iface);
+);
+
+enum {
+       PROP_0,
+       PROP_ATTRIBUTES,
+       PROP_LABEL,
+       PROP_CREATED,
+       PROP_MODIFIED,
+       PROP_VALUE
+};
+
+static void
+secret_file_item_init (SecretFileItem *self)
+{
+}
+
+static void
+secret_file_item_set_property (GObject *object,
+                               guint prop_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+       SecretFileItem *self = SECRET_FILE_ITEM (object);
+
+       switch (prop_id) {
+       case PROP_ATTRIBUTES:
+               self->attributes = g_value_dup_boxed (value);
+               break;
+       case PROP_LABEL:
+               self->label = g_value_dup_string (value);
+               break;
+       case PROP_CREATED:
+               self->created = g_value_get_uint64 (value);
+               break;
+       case PROP_MODIFIED:
+               self->modified = g_value_get_uint64 (value);
+               break;
+       case PROP_VALUE:
+               self->value = g_value_dup_boxed (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+secret_file_item_get_property (GObject *object,
+                               guint prop_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+       SecretFileItem *self = SECRET_FILE_ITEM (object);
+
+       switch (prop_id) {
+       case PROP_ATTRIBUTES:
+               g_value_set_boxed (value, self->attributes);
+               break;
+       case PROP_LABEL:
+               g_value_set_string (value, self->label);
+               break;
+       case PROP_CREATED:
+               g_value_set_uint64 (value, self->created);
+               break;
+       case PROP_MODIFIED:
+               g_value_set_uint64 (value, self->modified);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+secret_file_item_finalize (GObject *object)
+{
+       SecretFileItem *self = SECRET_FILE_ITEM (object);
+
+       g_hash_table_unref (self->attributes);
+       g_free (self->label);
+       secret_value_unref (self->value);
+       G_OBJECT_CLASS (secret_file_item_parent_class)->finalize (object);
+}
+
+static void
+secret_file_item_class_init (SecretFileItemClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+       gobject_class->set_property = secret_file_item_set_property;
+       gobject_class->get_property = secret_file_item_get_property;
+       gobject_class->finalize = secret_file_item_finalize;
+
+       g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+       g_object_class_override_property (gobject_class, PROP_LABEL, "label");
+       g_object_class_override_property (gobject_class, PROP_CREATED, "created");
+       g_object_class_override_property (gobject_class, PROP_MODIFIED, "modified");
+       g_object_class_install_property (gobject_class, PROP_VALUE,
+                  g_param_spec_boxed ("value", "Value", "Value",
+                                      SECRET_TYPE_VALUE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+}
+
+static void
+secret_file_item_retrieve_secret (SecretRetrievable *retrievable,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+       SecretFileItem *self = SECRET_FILE_ITEM (retrievable);
+       GTask *task = g_task_new (retrievable, cancellable, callback, user_data);
+
+       g_task_return_pointer (task,
+                              secret_value_ref (self->value),
+                              secret_value_unref);
+       g_object_unref (task);
+}
+
+static SecretRetrievable *
+secret_file_item_retrieve_secret_finish (SecretRetrievable *retrievable,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, retrievable), NULL);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+secret_file_item_retrievable_iface (SecretRetrievable *iface)
+{
+       iface->retrieve_secret = secret_file_item_retrieve_secret;
+       iface->retrieve_secret_finish = secret_file_item_retrieve_secret_finish;
+}
+
+static GHashTable *
+variant_to_attributes (GVariant *variant)
+{
+       GVariantIter iter;
+       gchar *key;
+       gchar *value;
+
+       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, "{ss}", &key, &value))
+               g_hash_table_insert (attributes, key, value);
+
+       return attributes;
+}
+
+static SecretValue *
+variant_to_secret_value (GVariant *variant)
+{
+       const gchar *value;
+       gsize n_value;
+
+       value = g_variant_get_fixed_array (array, &n_value, sizeof(guint8));
+       return secret_value_new (value, n_value);
+}
+
+SecretFileItem *
+secret_file_item_deserialize (GVariant *serialized)
+{
+       GVariant *attributes;
+       const gchar *label;
+       guint64 created;
+       guint64 modified;
+       GVariant *array;
+       SecretValue *value;
+       SecretFileItem *result;
+
+       g_variant_get (serialized, "(@a{ss}&stt@ay)",
+                      &attributes, &label, &created, &modified, &array);
+
+       value = variant_to_secret_value (array);
+       result = g_object_new (SECRET_TYPE_FILE_ITEM,
+                              "attributes", variant_to_attributes (attributes),
+                              "label", label,
+                              "created", created,
+                              "modified", modified,
+                              "value", value);
+       g_variant_unref (attributes);
+       g_variant_unref (array);
+       secret_value_unref (value);
+
+       return result;
+}
+
+GVariant *
+secret_file_item_serialize (SecretFileItem *self)
+{
+       GVariantBuilder builder;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       GVariant *array;
+       const gchar *secret;
+       gsize n_secret;
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+       g_hash_table_iter_init (&iter, self->attributes);
+       while (g_hash_table_iter_next (&iter, &key, &value))
+               g_variant_builder_add (&builder, "{ss}", key, value);
+
+       secret = secret_value_get (self->value, &n_secret);
+       array = g_variant_new_fixed_array (G_VARIANT_TYPE ("y"),
+                                          secret, n_secret, sizeof(guint8));
+
+       return g_variant_new ("(a{ss}stt@ay)",
+                             g_variant_builder_end (&builder),
+                             self->label,
+                             self->created,
+                             self->modified,
+                             array);
+}
diff --git a/libsecret/secret-file-item.h b/libsecret/secret-file-item.h
new file mode 100644
index 0000000..314d5be
--- /dev/null
+++ b/libsecret/secret-file-item.h
@@ -0,0 +1,32 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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.
+ *
+ * Author: Daiki Ueno
+ */
+
+#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION)
+#error "Only <libsecret/secret.h> can be included directly."
+#endif
+
+#ifndef __SECRET_FILE_ITEM_H__
+#define __SECRET_FILE_ITEM_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define SECRET_TYPE_FILE_ITEM (secret_file_item_get_type ())
+G_DECLARE_FINAL_TYPE (SecretFileItem, secret_file_item, SECRET, FILE_ITEM, GObject)
+
+SecretFileItem *secret_file_item_deserialize (GVariant *serialized);
+GVariant *secret_file_item_serialize (SecretFileItem *self);
+
+#endif /* __SECRET_FILE_ITEM_H__ */
diff --git a/libsecret/secret-file.c b/libsecret/secret-file.c
new file mode 100644
index 0000000..9555094
--- /dev/null
+++ b/libsecret/secret-file.c
@@ -0,0 +1,528 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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.
+ *
+ * Author: Daiki Ueno
+ */
+
+#include "config.h"
+
+#include "secret-file.h"
+#include "secret-file-item.h"
+
+static void secret_file_async_initable_iface (GAsyncInitableIface *iface);
+static void secret_file_backend_iface (SecretBackendInterface *iface);
+
+struct _SecretFile {
+       GObject parent;
+       gchar *path;
+       gchar *etag;
+       GBytes *key;
+       GBytes *iv;
+       GVariant *items;
+};
+
+G_DEFINE_TYPE_WITH_CODE (SecretFile, secret_file, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_file_async_initable_iface);
+                        G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_file_backend_iface);
+                        _secret_backend_ensure_extension_point ();
+                        g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME,
+                                                        g_define_type_id,
+                                                        "service",
+                                                        0)
+);
+
+#define MAC_ALGO GCRY_MAC_HMAC_SHA256
+#define MAC_SIZE 32
+
+#define CIPHER_ALGO GCRY_CIPHER_AES128
+#define IV_SIZE 16
+
+#define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
+#define KEYRING_FILE_HEADER_LEN 16
+
+enum {
+       PROP_0,
+       PROP_PATH,
+       PROP_KEY
+};
+
+static void
+secret_file_init (SecretFile *self)
+{
+}
+
+static void
+secret_file_finalize (GObject *object)
+{
+       SecretFile *self = SECRET_FILE (object);
+
+       g_bytes_unref (self->key);
+       g_bytes_unref (self->iv);
+       g_clear_pointer (&self->items, g_variant_unref)
+
+       G_OBJECT_CLASS (secret_file_parent_class)->finalize (object);
+}
+
+static void
+secret_file_class_init (SecretFileClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = secret_file_finalize;
+
+       /**
+        * SecretFile:flags:
+        *
+        * A set of flags describing which parts of the secret file have
+        * been initialized.
+        */
+       g_object_class_override_property (object_class, PROP_FLAGS, "flags");
+
+       /**
+        * SecretFile:path:
+        *
+        * The path from which keyrings are read.
+        */
+       g_object_class_install_property (object_class, PROP_PATH,
+                  g_param_spec_string ("path", "Path", "Path",
+                                       NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+on_load_contents (GObject *source_object,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+       GFile *file = G_FILE (source_object);
+       GTask *task = G_TASK (user_data);
+       SecretFile *self = g_task_get_task_data (task);
+       gchar *contents;
+       gchar *p;
+       gsize length;
+       GError *error = NULL;
+
+       if (!g_file_load_contents_finish (file, result,
+                                         &contents, &length,
+                                         &self->etag,
+                                         &error)) {
+               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+                       GVariantBuilder builder;
+                       guint8 iv[IV_SIZE];
+
+                       g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(a{say}ay)"));
+                       gcry_create_nonce (iv, sizeof(iv));
+                       self->iv = g_bytes_new (iv, sizeof(iv));
+                       self->items = g_variant_builder_end (&builder);
+                       g_task_return_boolean (task, TRUE);
+                       g_object_unref (task);
+               }
+
+               g_object_unref (file);
+               g_task_return_error (task, error);
+               g_object_unref (task);
+               return;
+       }
+
+       g_object_unref (file);
+
+       p = contents;
+       if (length < KEYRING_FILE_HEADER_LEN ||
+           memcmp (p, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN) != 0) {
+               g_task_return_new_error (task,
+                                        SECRET_ERROR,
+                                        SECRET_ERROR_PROTOCOL,
+                                        "file header mismatch");
+               g_object_unref (task);
+               return;
+       }
+       p += KEYRING_FILE_HEADER_LEN;
+       length -= KEYRING_FILE_HEADER_LEN;
+
+       if (length < 2 || *p != 1 || *(p + 1) != 0) {
+               g_task_return_new_error (task,
+                                        SECRET_ERROR,
+                                        SECRET_ERROR_PROTOCOL,
+                                        "version mismatch");
+               g_object_unref (task);
+               return;
+       }
+       p += 2;
+       length += 2;
+
+       if (length < IV_SIZE) {
+               g_task_return_new_error (task,
+                                        SECRET_ERROR,
+                                        SECRET_ERROR_PROTOCOL,
+                                        "invalid iv");
+               g_object_unref (task);
+               return;
+       }
+       self->iv = g_bytes_new (p, IV_SIZE);
+       p += IV_SIZE;
+       length += IV_SIZE;
+
+       self->items = g_variant_new_from_data (G_VARIANT_TYPE ("a{say}ay"),
+                                              p,
+                                              length,
+                                              TRUE,
+                                              g_free,
+                                              contents);
+       g_task_return_boolean (task, TRUE);
+       g_object_unref (task);
+}
+
+static void
+secret_file_real_init_async (GAsyncInitable *initable,
+                            int io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+       SecretFile *self = SECRET_FILE (initable);
+       GTask *task;
+       GFile *file;
+
+       task = g_task_new (initable, cancellable, callback, user_data);
+
+       file = g_file_new_for_path (self->path);
+       g_file_load_contents_async (file,
+                                   cancellable,
+                                   on_load_contents,
+                                   task);
+}
+
+static gboolean
+secret_file_real_init_async_finish (GAsyncInitable *initable,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+secret_file_async_initable_iface (GAsyncInitableIface *iface)
+{
+}
+
+static gboolean
+calculate_mac (SecretFile *self,
+              const guint8 *value, gsize n_value,
+              guint8 *buffer)
+{
+       gcry_mac_hd_t hd;
+       gcry_error_t gcry;
+       gboolean ret = FALSE;
+
+       gcry = gcry_mac_open (&hd, MAC_ALGO, 0, NULL);
+       g_return_val_if_fail (gcry == 0, FALSE);
+
+       gcry = gcry_mac_setkey (hd,
+                               g_bytes_get_data (self->key),
+                               g_bytes_get_size (self->key));
+       if (gcry != 0)
+               goto out;
+
+       gcry = gcry_mac_write (hd, value, strlen ((char *)value));
+       if (gcry != 0)
+               goto out;
+
+       gcry = gcry_mac_read (hd, buffer, sizeof(buffer));
+       if (gcry != 0)
+               goto out;
+
+       ret = TRUE;
+ out:
+       gcry_mac_close (hd);
+       return ret;
+}
+
+static gboolean
+decrypt (SecretFile *self,
+        guint8 *data,
+        gsize n_data)
+{
+       gcry_cipher_hd_t hd;
+       gcry_error_t gcry;
+       gboolean ret = FALSE;
+
+       gcry = gcry_cipher_open (&hd,
+                                GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC,
+                                0);
+       if (gcry != 0)
+               goto out;
+
+       gcry = gcry_cipher_setkey (hd,
+                                  g_bytes_get_data (self->key),
+                                  g_bytes_get_size (self->key));
+       if (gcry != 0)
+               goto out;
+
+       gcry = gcry_cipher_setiv (hd,
+                                 g_bytes_get_data (self->iv),
+                                 g_bytes_get_size (self->iv));
+       if (gcry != 0)
+               goto out;
+
+       gcry = gcry_cipher_decrypt (hd, data, n_data, NULL, 0);
+       if (gcry != 0)
+               goto out;
+
+       ret = TRUE;
+ out:
+       (void) gcry_cipher_final (hd);
+       return ret;
+}
+
+static void
+secret_file_real_store (SecretBackend *backend,
+                       const SecretSchema *schema,
+                       GHashTable *attributes,
+                       const gchar *collection,
+                       const gchar *label,
+                       SecretValue *value,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+       SecretFile *self = SECRET_FILE (backend);
+       GTask *task;
+       GVariantBuilder builder;
+       GVariant *hashed_attributes;
+       GVariantIter items;
+       GVariant *child;
+       GHashTableIter iter;
+       gpointer key;
+       gpointer value;
+       guint8 buffer[MAC_SIZE];
+       SecretFileItem *item;
+
+       task = g_task_new (self, cancellable, callback, user_data);
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{say}"));
+       g_hash_table_iter_init (&iter, attributes);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               if (!calculate_mac (self, value, strlen ((char *)value), buffer)) {
+                       g_task_return_new_error (task,
+                                                SECRET_ERROR,
+                                                SECRET_ERROR_PROTOCOL,
+                                                "couldn't calculate mac");
+                       g_object_unref (task);
+                       return;
+               }
+               g_variant_builder_add (&builder, "{say}", key, buffer);
+       }
+       hashed_attributes = g_variant_builder_end (&builder);
+
+       /* Filter out the existing item */
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{say}ay"));
+       g_variant_iter_init (&items, self->items);
+       while ((child = g_variant_iter_next_value (&items)) != NULL) {
+               if (!item_matches_attributes (child, attributes))
+                       g_variant_builder_add_value (&builder, child);
+               else
+                       g_variant_unref (child);
+       }
+       g_variant_unref (self->items);
+       self->items = g_variant_builder_end (&builder);
+}
+
+static gboolean
+secret_file_real_store_finish (SecretBackend *backend,
+                              GAsyncResult *result,
+                              GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, backend), NULL);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static gboolean
+item_matches_attributes (SecretFile *self,
+                        GVariant *item,
+                        GHashTable *attributes)
+{
+       GHashTableIter iter;
+       GVariant *hashed_attributes = NULL;
+       GVariant *hashed_attribute = NULL;
+       gpointer key;
+       gpointer value;
+       guint8 buffer[MAC_SIZE];
+       gboolean ret = TRUE;
+
+       g_variant_get (item, "@a{say}ay", &hashed_attributes, NULL);
+
+       g_hash_table_iter_init (&iter, attributes);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               const guint8 *data;
+               gsize n_data;
+
+               if (!g_variant_lookup (hashed_attributes, key,
+                                      "@ay", &hashed_attribute)) {
+                       ret = FALSE;
+                       goto out;
+               }
+
+               data = g_variant_get_fixed_array (hashed_attribute,
+                                                 &n_data, sizeof(guint8));
+               if (n_data != MAC_SIZE) {
+                       ret = FALSE;
+                       goto out;
+               }
+
+               calculate_mac (self, value, strlen ((char *)value), buffer);
+               if (memcmp (data, buffer, MAC_SIZE) != 0) {
+                       ret = FALSE;
+                       goto out;
+               }
+       }
+ out:
+       g_clear_pointer (&hashed_attributes, g_variant_unref);
+       g_clear_pointer (&hashed_attribute, g_variant_unref);
+       return ret;
+}
+
+static void
+on_retrieve_secret (GObject *source_object,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+       SecretRetrievable *retrievable = SECRET_RETRIEVABLE (source_object);
+       GTask *task = G_TASK (user_data);
+       SecretValue *value;
+       GError *error;
+
+       value = secret_retrievable_retrieve_secret_finish (retrievable,
+                                                          result,
+                                                          &error);
+       if (value == NULL) {
+               g_task_return_error (task, error);
+               g_object_unref (task);
+       }
+       g_task_return_pointer (task, value, secret_value_unref);
+       g_object_unref (task);
+}
+
+static void
+secret_file_real_lookup (SecretBackend *backend,
+                        const SecretSchema *schema,
+                        GHashTable *attributes,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+       SecretFile *self = SECRET_FILE (backend);
+       GTask *task = g_task_new (self, cancellable, callback, user_data);
+       GVariantIter iter;
+       GVariant *child;
+       SecretFileItem *item;
+       const guint8 *data;
+       gsize n_data;
+       GVariant *blob;
+       guint8 *buffer;
+
+       g_variant_iter_init (&iter, self->items);
+       while ((child = g_variant_iter_next_value (&iter)) != NULL) {
+               if (item_matches_attributes (child, attributes))
+                       break;
+               g_variant_unref (child);
+       }
+
+       if (child == NULL) {
+               g_task_return_pointer (task, NULL, NULL);
+               g_object_unref (task);
+               return;
+       }
+
+       g_variant_get (child, "a{say}@ay", NULL, &blob);
+       data = g_variant_get_fixed_array (blob, &n_data, sizeof(guint8));
+       buffer = egg_secure_alloc (n_data);
+       memcpy (buffer, data, n_data);
+       g_variant_unref (blob);
+       g_variant_unref (child);
+
+       if (!decrypt (self, buffer, n_data)) {
+               egg_secure_free (buffer);
+               g_task_return_new_error (task,
+                                        SECRET_ERROR,
+                                        SECRET_ERROR_PROTOCOL,
+                                        "couldn't decrypt item");
+               g_object_unref (task);
+               return;
+       }
+
+       item = secret_file_item_deserialize (buffer, n_data);
+       egg_secure_free (buffer);
+
+       secret_retrievable_retrieve_secret (SECRET_RETRIEVABLE (item),
+                                           cancellable,
+                                           on_retrieve_secret,
+                                           task);
+}
+
+static SecretValue *
+secret_file_real_lookup_finish (SecretBackend *backend,
+                               GAsyncResult *result,
+                               GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, backend), NULL);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+secret_file_real_clear (SecretBackend *backend,
+                       const SecretSchema *schema,
+                       GHashTable *attributes,
+                       GCancellable *cancellable,
+                       GAsyncReadyCallback callback,
+                       gpointer user_data)
+{
+}
+
+static gboolean
+secret_file_real_clear_finish (SecretBackend *backend,
+                              GAsyncResult *result,
+                              GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, backend), NULL);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+secret_file_real_search (SecretBackend *backend,
+                        const SecretSchema *schema,
+                        GHashTable *attributes,
+                        SecretSearchFlags flags,
+                        GCancellable *cancellable,
+                        GAsyncReadyCallback callback,
+                        gpointer user_data)
+{
+}
+
+static GList *
+secret_file_real_search_finish (SecretBackend *backend,
+                               GAsyncResult *result,
+                               GError **error)
+{
+       g_return_val_if_fail (g_task_is_valid (result, backend), NULL);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+secret_file_backend_iface (SecretBackendInterface *iface)
+{
+       iface->store = secret_file_real_store;
+       iface->store_finish = secret_file_real_store_finish;
+}
diff --git a/libsecret/secret-file.h b/libsecret/secret-file.h
new file mode 100644
index 0000000..1aabd3a
--- /dev/null
+++ b/libsecret/secret-file.h
@@ -0,0 +1,31 @@
+/* libsecret - GLib wrapper for Secret Service
+ *
+ * Copyright 2019 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.
+ *
+ * Author: Daiki Ueno
+ */
+
+#if !defined (__SECRET_INSIDE_HEADER__) && !defined (SECRET_COMPILATION)
+#error "Only <libsecret/secret.h> can be included directly."
+#endif
+
+#ifndef __SECRET_FILE_H__
+#define __SECRET_FILE_H__
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+
+#define SECRET_TYPE_FILE (secret_file_get_type ())
+G_DECLARE_FINAL_TYPE (SecretFile, secret_file, SECRET, FILE, GObject)
+
+G_END_DECLS
+
+#endif /* __SECRET_FILE_H__ */
diff --git a/libsecret/secret-item.c b/libsecret/secret-item.c
index a5eb7cf..a47432d 100644
--- a/libsecret/secret-item.c
+++ b/libsecret/secret-item.c
@@ -121,7 +121,8 @@ static void   secret_item_async_initable_iface   (GAsyncInitableIface *iface);
 G_DEFINE_TYPE_WITH_CODE (SecretItem, secret_item, G_TYPE_DBUS_PROXY,
                          G_ADD_PRIVATE (SecretItem)
                         G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_item_retrievable_iface);
-                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_initable_iface);
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_init
+able_iface);
                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_item_async_initable_iface);
 );
 


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