gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] branch master updated (0d8f1fa2 -> 25fe8df2)


From: gnunet
Subject: [taler-exchange] branch master updated (0d8f1fa2 -> 25fe8df2)
Date: Thu, 16 Nov 2023 15:38:04 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from 0d8f1fa2 remove is_currency_name_leading
     new 758afecc add logic to serve AML SPA
     new 288286e0 -fix typo in SQL
     new 25fe8df2 add wallet-core submodule for SPA

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitmodules                             |   4 +
 bootstrap                               |  13 ++
 contrib/{Makefile.am => Makefile.am.in} |   8 +
 contrib/wallet-core                     |   1 +
 src/exchange/Makefile.am                |   3 +-
 src/exchange/taler-exchange-httpd.c     |  74 ++++++-
 src/exchange/taler-exchange-httpd_spa.c | 362 ++++++++++++++++++++++++++++++++
 src/exchange/taler-exchange-httpd_spa.h |  49 +++++
 src/exchangedb/pg_trigger_aml_process.c |   2 +-
 9 files changed, 507 insertions(+), 9 deletions(-)
 rename contrib/{Makefile.am => Makefile.am.in} (84%)
 create mode 160000 contrib/wallet-core
 create mode 100644 src/exchange/taler-exchange-httpd_spa.c
 create mode 100644 src/exchange/taler-exchange-httpd_spa.h

diff --git a/.gitmodules b/.gitmodules
index f2b9611b..18e1227d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -8,3 +8,7 @@
 [submodule "contrib/gana"]
        path = contrib/gana
        url = https://git.gnunet.org/gana.git
+[submodule "contrib/wallet-core"]
+       path = contrib/wallet-core
+       url = https://git.taler.net/wallet-core.git
+       branch = prebuilt
diff --git a/bootstrap b/bootstrap
index da4f6320..10bd617f 100755
--- a/bootstrap
+++ b/bootstrap
@@ -39,4 +39,17 @@ else
     echo "Uncrustify not detected, hook not installed. Please install 
uncrustify if you plan on doing development"
 fi
 
+
+# Generate Makefile.am in contrib/
+cd contrib
+rm -f Makefile.am
+find wallet-core/aml-backoffice/ -type f -printf '  %p \\\n' | sort > 
Makefile.am.ext
+# Remove extra '\' at the end of the file
+truncate -s -2 Makefile.am.ext
+cat Makefile.am.in Makefile.am.ext >> Makefile.am
+# Prevent accidental editing of the generated Makefile.am
+chmod -w Makefile.am
+cd ..
+
+echo "$0: Running autoreconf"
 autoreconf -fi
diff --git a/contrib/Makefile.am b/contrib/Makefile.am.in
similarity index 84%
rename from contrib/Makefile.am
rename to contrib/Makefile.am.in
index 09e1dcf9..64a5a9f5 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am.in
@@ -61,3 +61,11 @@ EXTRA_DIST = \
   gnunet.tag \
   microhttpd.tag \
   packages
+
+spapkgdatadir = $(prefix)/share/taler/exchange/spa/
+
+# This is for the single-page-app imported from the wallet-core.git
+# prebuilt branch. This MUST be the last line in the
+# Makefile.am.in, as it will be combined with the
+# actual SPA data by 'bootstrap'!
+dist_spapkgdata_DATA = \
diff --git a/contrib/wallet-core b/contrib/wallet-core
new file mode 160000
index 00000000..621dad2c
--- /dev/null
+++ b/contrib/wallet-core
@@ -0,0 +1 @@
+Subproject commit 621dad2c2ec9a2adc52076cebf65891d6764c802
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 12ea34e1..7d0e5a33 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -181,8 +181,9 @@ taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd_reserves_open.c taler-exchange-httpd_reserves_open.h \
   taler-exchange-httpd_reserves_purse.c taler-exchange-httpd_reserves_purse.h \
   taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
+  taler-exchange-httpd_spa.c taler-exchange-httpd_spa.h \
   taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
-  taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h 
+  taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h
 
 taler_exchange_httpd_LDADD = \
   $(LIBGCRYPT_LIBS) \
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 7c777756..1cde5816 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -68,6 +68,7 @@
 #include "taler-exchange-httpd_reserves_history.h"
 #include "taler-exchange-httpd_reserves_open.h"
 #include "taler-exchange-httpd_reserves_purse.h"
+#include "taler-exchange-httpd_spa.h"
 #include "taler-exchange-httpd_terms.h"
 #include "taler-exchange-httpd_transfers_get.h"
 #include "taler_exchangedb_lib.h"
@@ -1507,6 +1508,56 @@ handle_post_auditors (struct TEH_RequestContext *rc,
 }
 
 
+/**
+ * Generates the response for "/", redirecting the
+ * client to the "/webui/" from where we serve the SPA.
+ *
+ * @param rc request context
+ * @param args remaining arguments (should be empty)
+ * @return MHD result code
+ */
+static MHD_RESULT
+spa_redirect (struct TEH_RequestContext *rc,
+              const char *const args[])
+{
+  const char *text = "Redirecting to /webui/";
+  struct MHD_Response *response;
+
+  response = MHD_create_response_from_buffer (strlen (text),
+                                              (void *) text,
+                                              MHD_RESPMEM_PERSISTENT);
+  if (NULL == response)
+  {
+    GNUNET_break (0);
+    return MHD_NO;
+  }
+  TALER_MHD_add_global_headers (response);
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (response,
+                                         MHD_HTTP_HEADER_CONTENT_TYPE,
+                                         "text/plain"));
+  if (MHD_NO ==
+      MHD_add_response_header (response,
+                               MHD_HTTP_HEADER_LOCATION,
+                               "/webui/"))
+  {
+    GNUNET_break (0);
+    MHD_destroy_response (response);
+    return MHD_NO;
+  }
+
+  {
+    MHD_RESULT ret;
+
+    ret = MHD_queue_response (rc->connection,
+                              MHD_HTTP_FOUND,
+                              response);
+    MHD_destroy_response (response);
+    return ret;
+  }
+}
+
+
 /**
  * Handle incoming HTTP request.
  *
@@ -1540,15 +1591,11 @@ handle_mhd_request (void *cls,
       .data = "User-agent: *\nDisallow: /\n",
       .response_code = MHD_HTTP_OK
     },
-    /* Landing page, tell humans to go away. */
+    /* Landing page, redirect to SPA */
     {
       .url = "",
       .method = MHD_HTTP_METHOD_GET,
-      .handler.get = TEH_handler_static_response,
-      .mime_type = "text/plain",
-      .data =
-        "Hello, I'm the Taler exchange. This HTTP server is not for humans.\n",
-      .response_code = MHD_HTTP_OK
+      .handler.get = &spa_redirect
     },
     /* AGPL licensing page, redirect to source. As per the AGPL-license, every
        deployment is required to offer the user a download of the source of
@@ -1778,7 +1825,13 @@ handle_mhd_request (void *cls,
       .handler.post = &handle_post_aml,
       .nargs = 2
     },
-
+    {
+      .url = "webui",
+      .method = MHD_HTTP_METHOD_GET,
+      .handler.get = &TEH_handler_spa,
+      .nargs = 1,
+      .nargs_is_upper_bound = true
+    },
 
     /* mark end of list */
     {
@@ -2542,6 +2595,13 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
+  if (GNUNET_OK !=
+      TEH_spa_init ())
+  {
+    global_ret = EXIT_NOTCONFIGURED;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
   if (GNUNET_OK !=
       TALER_TEMPLATING_init ("exchange"))
   {
diff --git a/src/exchange/taler-exchange-httpd_spa.c 
b/src/exchange/taler-exchange-httpd_spa.c
new file mode 100644
index 00000000..66b6fdcf
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_spa.c
@@ -0,0 +1,362 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2020, 2023 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of EXCHANGEABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_spa.c
+ * @brief logic to load the single page app (/)
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <taler/taler_util.h>
+#include <taler/taler_mhd_lib.h>
+#include <gnunet/gnunet_mhd_compat.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Resource from the WebUi.
+ */
+struct WebuiFile
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct WebuiFile *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct WebuiFile *prev;
+
+  /**
+   * Path this resource matches.
+   */
+  char *path;
+
+  /**
+   * SPA resource, compressed.
+   */
+  struct MHD_Response *zspa;
+
+  /**
+   * SPA resource, vanilla.
+   */
+  struct MHD_Response *spa;
+
+};
+
+
+/**
+ * Resources of the WebuUI, kept in a DLL.
+ */
+static struct WebuiFile *webui_head;
+
+/**
+ * Resources of the WebuUI, kept in a DLL.
+ */
+static struct WebuiFile *webui_tail;
+
+
+MHD_RESULT
+TEH_handler_spa (struct TEH_RequestContext *rc,
+                 const char *const args[])
+{
+  struct WebuiFile *w = NULL;
+  const char *infix = args[0];
+
+  if ( (NULL == infix) ||
+       (0 == strcmp (infix,
+                     "")) )
+    infix = "index.html";
+  for (struct WebuiFile *pos = webui_head;
+       NULL != pos;
+       pos = pos->next)
+    if (0 == strcmp (infix,
+                     pos->path))
+    {
+      w = pos;
+      break;
+    }
+  if (NULL == w)
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_NOT_FOUND,
+                                       TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+                                       rc->url);
+  if ( (MHD_YES ==
+        TALER_MHD_can_compress (rc->connection)) &&
+       (NULL != w->zspa) )
+    return MHD_queue_response (rc->connection,
+                               MHD_HTTP_OK,
+                               w->zspa);
+  return MHD_queue_response (rc->connection,
+                             MHD_HTTP_OK,
+                             w->spa);
+}
+
+
+/**
+ * Function called on each file to load for the WebUI.
+ *
+ * @param cls NULL
+ * @param dn name of the file to load
+ */
+static enum GNUNET_GenericReturnValue
+build_webui (void *cls,
+             const char *dn)
+{
+  static struct
+  {
+    const char *ext;
+    const char *mime;
+  } mime_map[] = {
+    {
+      .ext = "css",
+      .mime = "text/css"
+    },
+    {
+      .ext = "html",
+      .mime = "text/html"
+    },
+    {
+      .ext = "js",
+      .mime = "text/javascript"
+    },
+    {
+      .ext = "jpg",
+      .mime = "image/jpeg"
+    },
+    {
+      .ext = "jpeg",
+      .mime = "image/jpeg"
+    },
+    {
+      .ext = "png",
+      .mime = "image/png"
+    },
+    {
+      .ext = "svg",
+      .mime = "image/svg+xml"
+    },
+    {
+      .ext = NULL,
+      .mime = NULL
+    },
+  };
+  int fd;
+  struct stat sb;
+  struct MHD_Response *zspa = NULL;
+  struct MHD_Response *spa;
+  const char *ext;
+  const char *mime;
+
+  (void) cls;
+  /* finally open template */
+  fd = open (dn,
+             O_RDONLY);
+  if (-1 == fd)
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                              "open",
+                              dn);
+    return GNUNET_SYSERR;
+  }
+  if (0 !=
+      fstat (fd,
+             &sb))
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                              "open",
+                              dn);
+    GNUNET_break (0 == close (fd));
+    return GNUNET_SYSERR;
+  }
+
+  mime = NULL;
+  ext = strrchr (dn, '.');
+  if (NULL == ext)
+  {
+    GNUNET_break (0 == close (fd));
+    return GNUNET_OK;
+  }
+  ext++;
+  for (unsigned int i = 0; NULL != mime_map[i].ext; i++)
+    if (0 == strcasecmp (ext,
+                         mime_map[i].ext))
+    {
+      mime = mime_map[i].mime;
+      break;
+    }
+
+  {
+    void *in;
+    ssize_t r;
+    size_t csize;
+
+    in = GNUNET_malloc_large (sb.st_size);
+    if (NULL == in)
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                           "malloc");
+      GNUNET_break (0 == close (fd));
+      return GNUNET_SYSERR;
+    }
+    r = read (fd,
+              in,
+              sb.st_size);
+    if ( (-1 == r) ||
+         (sb.st_size != (size_t) r) )
+    {
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                                "read",
+                                dn);
+      GNUNET_free (in);
+      GNUNET_break (0 == close (fd));
+      return GNUNET_SYSERR;
+    }
+    csize = (size_t) r;
+    if (MHD_YES ==
+        TALER_MHD_body_compress (&in,
+                                 &csize))
+    {
+      zspa = MHD_create_response_from_buffer (csize,
+                                              in,
+                                              MHD_RESPMEM_MUST_FREE);
+      if (NULL != zspa)
+      {
+        if (MHD_NO ==
+            MHD_add_response_header (zspa,
+                                     MHD_HTTP_HEADER_CONTENT_ENCODING,
+                                     "deflate"))
+        {
+          GNUNET_break (0);
+          MHD_destroy_response (zspa);
+          zspa = NULL;
+        }
+        if (NULL != mime)
+          GNUNET_break (MHD_YES ==
+                        MHD_add_response_header (zspa,
+                                                 MHD_HTTP_HEADER_CONTENT_TYPE,
+                                                 mime));
+      }
+    }
+    else
+    {
+      GNUNET_free (in);
+    }
+  }
+
+  spa = MHD_create_response_from_fd (sb.st_size,
+                                     fd);
+  if (NULL == spa)
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                              "open",
+                              dn);
+    GNUNET_break (0 == close (fd));
+    if (NULL != zspa)
+    {
+      MHD_destroy_response (zspa);
+      zspa = NULL;
+    }
+    return GNUNET_SYSERR;
+  }
+  if (NULL != mime)
+    GNUNET_break (MHD_YES ==
+                  MHD_add_response_header (spa,
+                                           MHD_HTTP_HEADER_CONTENT_TYPE,
+                                           mime));
+
+  {
+    struct WebuiFile *w;
+    const char *fn;
+
+    fn = strrchr (dn, '/');
+    GNUNET_assert (NULL != fn);
+    w = GNUNET_new (struct WebuiFile);
+    w->path = GNUNET_strdup (fn + 1);
+    w->spa = spa;
+    w->zspa = zspa;
+    GNUNET_CONTAINER_DLL_insert (webui_head,
+                                 webui_tail,
+                                 w);
+  }
+  return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TEH_spa_init ()
+{
+  char *dn;
+
+  {
+    char *path;
+
+    path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
+    if (NULL == path)
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_asprintf (&dn,
+                     "%sexchange/spa/",
+                     path);
+    GNUNET_free (path);
+  }
+
+  if (-1 ==
+      GNUNET_DISK_directory_scan (dn,
+                                  &build_webui,
+                                  NULL))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to load WebUI from `%s'\n",
+                dn);
+    GNUNET_free (dn);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (dn);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Nicely shut down.
+ */
+void __attribute__ ((destructor))
+get_spa_fini ()
+{
+  struct WebuiFile *w;
+
+  while (NULL != (w = webui_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (webui_head,
+                                 webui_tail,
+                                 w);
+    if (NULL != w->spa)
+    {
+      MHD_destroy_response (w->spa);
+      w->spa = NULL;
+    }
+    if (NULL != w->zspa)
+    {
+      MHD_destroy_response (w->zspa);
+      w->zspa = NULL;
+    }
+    GNUNET_free (w->path);
+    GNUNET_free (w);
+  }
+}
diff --git a/src/exchange/taler-exchange-httpd_spa.h 
b/src/exchange/taler-exchange-httpd_spa.h
new file mode 100644
index 00000000..4147a853
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_spa.h
@@ -0,0 +1,49 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2023 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of EXCHANGEABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_spa.h
+ * @brief logic to preload and serve static files
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_SPA_H
+#define TALER_EXCHANGE_HTTPD_SPA_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Return our single-page-app user interface (see contrib/wallet-core/).
+ *
+ * @param rc context of the handler
+ * @param[in,out] args remaining arguments (ignored)
+ * @return #MHD_YES on success (reply queued), #MHD_NO on error (close 
connection)
+ */
+MHD_RESULT
+TEH_handler_spa (struct TEH_RequestContext *rc,
+                 const char *const args[]);
+
+
+/**
+ * Preload and compress SPA files.
+ *
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TEH_spa_init (void);
+
+
+#endif
diff --git a/src/exchangedb/pg_trigger_aml_process.c 
b/src/exchangedb/pg_trigger_aml_process.c
index 0450eb71..a4873ae6 100644
--- a/src/exchangedb/pg_trigger_aml_process.c
+++ b/src/exchangedb/pg_trigger_aml_process.c
@@ -48,7 +48,7 @@ TEH_PG_trigger_aml_process (
            ",status)"
            "VALUES"
            "($1, $2, 1)" // 1: decision needed
-           "ON CONFLICT DO"
+           " ON CONFLICT DO"
            " UPDATE SET"
            "   threshold=$2"
            "  ,status=status | 1;"); // do not clear 'frozen' status

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]