[ostree] repo: Add ostree_repo_remote_fetch_summary()



commit 0dbf91484b8ec6e02ba4e19fec8fe96070b1f2c4
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Jun 7 13:41:04 2015 -0400

    repo: Add ostree_repo_remote_fetch_summary()
    
    Reusable method for fetching a summary file and signatures.

 doc/ostree-sections.txt     |    1 +
 src/libostree/ostree-repo.c |  271 +++++++++++++++++++++++++++++++++++++++++++
 src/libostree/ostree-repo.h |    7 +
 3 files changed, 279 insertions(+), 0 deletions(-)
---
diff --git a/doc/ostree-sections.txt b/doc/ostree-sections.txt
index 92cded7..8149b5e 100644
--- a/doc/ostree-sections.txt
+++ b/doc/ostree-sections.txt
@@ -234,6 +234,7 @@ ostree_repo_remote_list
 ostree_repo_remote_get_url
 ostree_repo_remote_get_gpg_verify
 ostree_repo_remote_gpg_import
+ostree_repo_remote_fetch_summary
 ostree_repo_get_parent
 ostree_repo_write_config
 OstreeRepoTransactionStats
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index f7c2a4e..56f7b29 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -34,6 +34,7 @@
 #include "ostree-repo-file-enumerator.h"
 #include "ostree-gpg-verifier.h"
 #include "ostree-repo-static-delta-private.h"
+#include "ostree-metalink.h"
 
 #include <locale.h>
 #include <glib/gstdio.h>
@@ -1577,6 +1578,276 @@ out:
 }
 
 static gboolean
+repo_remote_fetch_summary_url (OstreeRepo    *self,
+                               const char    *name,
+                               GBytes       **out_summary,
+                               GBytes       **out_signatures,
+                               GCancellable  *cancellable,
+                               GError       **error)
+{
+  glnx_unref_object OstreeFetcher *fetcher = NULL;
+  g_autoptr(GMainLoop) main_loop = NULL;
+  g_autofree char *url_string = NULL;
+  SoupURI *base_uri = NULL;
+  gboolean ret = FALSE;
+
+  if (!ostree_repo_remote_get_url (self, name, &url_string, error))
+    goto out;
+
+  base_uri = soup_uri_new (url_string);
+
+  if (base_uri == NULL)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Invalid URL '%s'", url_string);
+      goto out;
+    }
+
+  fetcher = _ostree_repo_remote_new_fetcher (self, name, error);
+
+  if (fetcher == NULL)
+    goto out;
+
+  main_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+
+  {
+    SoupURI *uri;
+    const char *base_path;
+    g_autofree char *path = NULL;
+
+    base_path = soup_uri_get_path (base_uri);
+    path = g_build_filename (base_path, "summary", NULL);
+    uri = soup_uri_new_with_base (base_uri, path);
+
+    ret = _ostree_fetcher_request_uri_to_membuf (fetcher, uri,
+                                                 FALSE, TRUE,
+                                                 out_summary,
+                                                 main_loop,
+                                                 OSTREE_MAX_METADATA_SIZE,
+                                                 cancellable, error);
+    soup_uri_free (uri);
+
+    if (!ret)
+      goto out;
+  }
+
+  {
+    SoupURI *uri;
+    const char *base_path;
+    g_autofree char *path = NULL;
+
+    base_path = soup_uri_get_path (base_uri);
+    path = g_build_filename (base_path, "summary.sig", NULL);
+    uri = soup_uri_new_with_base (base_uri, path);
+
+    ret = _ostree_fetcher_request_uri_to_membuf (fetcher, uri,
+                                                 FALSE, TRUE,
+                                                 out_signatures,
+                                                 main_loop,
+                                                 OSTREE_MAX_METADATA_SIZE,
+                                                 cancellable, error);
+    soup_uri_free (uri);
+
+    if (!ret)
+      goto out;
+  }
+
+out:
+  if (base_uri != NULL)
+    soup_uri_free (base_uri);
+
+  return ret;
+}
+
+static gboolean
+repo_remote_fetch_summary_metalink (OstreeRepo    *self,
+                                    const char    *name,
+                                    const char    *metalink_url_string,
+                                    GBytes       **out_summary,
+                                    GBytes       **out_signatures,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+  glnx_unref_object OstreeFetcher *fetcher = NULL;
+  g_autoptr(GMainLoop) main_loop = NULL;
+  SoupURI *metalink_uri = NULL;
+  gboolean ret = FALSE;
+
+  metalink_uri = soup_uri_new (metalink_url_string);
+
+  if (metalink_uri == NULL)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Invalid URL '%s'", metalink_url_string);
+      goto out;
+    }
+
+  fetcher = _ostree_repo_remote_new_fetcher (self, name, error);
+
+  if (fetcher == NULL)
+    goto out;
+
+  main_loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+
+  {
+    glnx_unref_object OstreeMetalink *metalink = NULL;
+    GError *local_error = NULL;
+
+    metalink = _ostree_metalink_new (fetcher, "summary",
+                                     OSTREE_MAX_METADATA_SIZE,
+                                     metalink_uri);
+
+    _ostree_metalink_request_sync (metalink, main_loop,
+                                   NULL, out_summary, NULL,
+                                   cancellable, &local_error);
+
+    if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+      {
+        g_clear_error (&local_error);
+        *out_summary = NULL;
+      }
+    else if (local_error != NULL)
+      {
+        g_propagate_error (error, local_error);
+        goto out;
+      }
+  }
+
+  {
+    glnx_unref_object OstreeMetalink *metalink = NULL;
+    GError *local_error = NULL;
+
+    metalink = _ostree_metalink_new (fetcher, "summary.sig",
+                                     OSTREE_MAX_METADATA_SIZE,
+                                     metalink_uri);
+
+    _ostree_metalink_request_sync (metalink, main_loop,
+                                   NULL, out_signatures, NULL,
+                                   cancellable, &local_error);
+
+    if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+      {
+        g_clear_error (&local_error);
+        *out_signatures = NULL;
+      }
+    else if (local_error != NULL)
+      {
+        g_propagate_error (error, local_error);
+        goto out;
+      }
+  }
+
+  ret = TRUE;
+
+out:
+  if (metalink_uri != NULL)
+    soup_uri_free (metalink_uri);
+
+  return ret;
+}
+
+/**
+ * ostree_repo_remote_fetch_summary:
+ * @self: Self
+ * @name: name of a remote
+ * @out_summary: (allow-none): return location for raw summary data, or %NULL
+ * @out_signatures: (allow-none): return location for raw summary signature
+ *                                data, or %NULL
+ * @cancellable: a #GCancellable
+ * @error: a #GError
+ *
+ * Tries to fetch the summary file and any GPG signatures on the summary file
+ * over HTTP, and returns the binary data in @out_summary and @out_signatures
+ * respectively.
+ *
+ * If no summary file exists on the remote server, @out_summary is set to
+ * @NULL.  Likewise if the summary file is not signed, @out_signatures is
+ * set to @NULL.  In either case the function still returns %TRUE.
+ *
+ * Parse the summary data into a #GVariant using g_variant_new_from_bytes()
+ * with #OSTREE_SUMMARY_GVARIANT_FORMAT as the format string.
+ *
+ * Returns: %TRUE on success, %FALSE on failure
+ */
+gboolean
+ostree_repo_remote_fetch_summary (OstreeRepo    *self,
+                                  const char    *name,
+                                  GBytes       **out_summary,
+                                  GBytes       **out_signatures,
+                                  GCancellable  *cancellable,
+                                  GError       **error)
+{
+  g_autofree char *metalink_url_string = NULL;
+  g_autoptr(GBytes) summary = NULL;
+  g_autoptr(GBytes) signatures = NULL;
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (OSTREE_REPO (self), FALSE);
+  g_return_val_if_fail (name != NULL, FALSE);
+
+  if (!_ostree_repo_get_remote_option (self, name, "metalink", NULL,
+                                       &metalink_url_string, error))
+    goto out;
+
+  if (metalink_url_string == NULL)
+    {
+      if (!repo_remote_fetch_summary_url (self, name,
+                                          &summary,
+                                          &signatures,
+                                          cancellable,
+                                          error))
+        goto out;
+    }
+  else
+    {
+      if (!repo_remote_fetch_summary_metalink (self, name,
+                                               metalink_url_string,
+                                               &summary,
+                                               &signatures,
+                                               cancellable,
+                                               error))
+        goto out;
+    }
+
+  /* Verify any summary signatures. */
+  if (summary != NULL && signatures != NULL)
+    {
+      glnx_unref_object OstreeGpgVerifyResult *result = NULL;
+      g_autoptr(GVariant) signatures_variant = NULL;
+
+      signatures_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT,
+                                                     signatures, FALSE);
+      result = _ostree_repo_gpg_verify_with_metadata (self,
+                                                      summary,
+                                                      signatures_variant,
+                                                      name,
+                                                      NULL, NULL,
+                                                      cancellable,
+                                                      error);
+      if (result == NULL)
+        goto out;
+
+      if (ostree_gpg_verify_result_count_valid (result) == 0)
+        {
+          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               "GPG signatures found, but none are in trusted keyring");
+          goto out;
+        }
+    }
+
+  if (out_summary != NULL)
+    *out_summary = g_steal_pointer (&summary);
+
+  if (out_signatures != NULL)
+    *out_signatures = g_steal_pointer (&signatures);
+
+  ret = TRUE;
+
+out:
+  return ret;
+}
+
+static gboolean
 ostree_repo_mode_to_string (OstreeRepoMode   mode,
                             const char     **out_mode,
                             GError         **error)
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 60b45dc..ce81c46 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -120,6 +120,13 @@ gboolean      ostree_repo_remote_gpg_import (OstreeRepo         *self,
                                              GCancellable       *cancellable,
                                              GError            **error);
 
+gboolean      ostree_repo_remote_fetch_summary (OstreeRepo    *self,
+                                                const char    *name,
+                                                GBytes       **out_summary,
+                                                GBytes       **out_signatures,
+                                                GCancellable  *cancellable,
+                                                GError       **error);
+
 OstreeRepo * ostree_repo_get_parent (OstreeRepo  *self);
 
 gboolean      ostree_repo_write_config (OstreeRepo *self,


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