commit e74b90750c0e7f63bc9a880efbde696399abe200
parent e35a990bff113edb25a5484f7a04689c3750a43d
Author: Sebastian <sebasjm@gmail.com>
Date: Wed, 3 Jul 2024 10:06:55 -0300
use challenger spa
Diffstat:
7 files changed, 502 insertions(+), 151 deletions(-)
diff --git a/contrib/Makefile.am.in b/contrib/Makefile.am.in
@@ -5,13 +5,13 @@ SUBDIRS = .
bin_SCRIPTS = \
challenger-dbconfig
-tmplpkgdatadir = $(prefix)/share/challenger/templates/
-
EXTRA_DIST = \
challenger-dbconfig
-# This is for the templates imported from the wallet-core.git
+spapkgdatadir = $(prefix)/share/challenger/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 file list by 'bootstrap'!
-dist_tmplpkgdata_DATA = \
+# actual SPA data by 'bootstrap'!
+dist_spapkgdata_DATA = \
diff --git a/src/challenger/Makefile.am b/src/challenger/Makefile.am
@@ -38,12 +38,12 @@ challenger_admin_LDADD = \
challenger_httpd_SOURCES = \
challenger-httpd.c challenger-httpd.h \
challenger-httpd_agpl.c challenger-httpd_agpl.h \
+ challenger-httpd_spa.c challenger-httpd_spa.h \
challenger-httpd_authorize.c challenger-httpd_authorize.h \
challenger-httpd_challenge.c challenger-httpd_challenge.h \
challenger-httpd_common.c challenger-httpd_common.h \
challenger-httpd_config.c challenger-httpd_config.h \
challenger-httpd_info.c challenger-httpd_info.h \
- challenger-httpd_main_css.c challenger-httpd_main_css.h \
challenger-httpd_mhd.c challenger-httpd_mhd.h \
challenger-httpd_setup.c challenger-httpd_setup.h \
challenger-httpd_solve.c challenger-httpd_solve.h \
diff --git a/src/challenger/challenger-httpd.c b/src/challenger/challenger-httpd.c
@@ -29,11 +29,11 @@
#include "challenger-httpd_challenge.h"
#include "challenger-httpd_config.h"
#include "challenger-httpd_info.h"
-#include "challenger-httpd_main_css.h"
#include "challenger-httpd_mhd.h"
#include "challenger-httpd_setup.h"
#include "challenger-httpd_solve.h"
#include "challenger-httpd_token.h"
+#include "challenger-httpd_spa.h"
#include "challenger_database_lib.h"
#include <taler/taler_templating_lib.h>
@@ -171,17 +171,17 @@ url_handler (void *cls,
{
.url = "/",
.method = MHD_HTTP_METHOD_GET,
- .handler = &CH_MHD_handler_root
+ .handler = &CH_spa_redirect
},
{
- .url = "/agpl",
+ .url = "/webui/",
.method = MHD_HTTP_METHOD_GET,
- .handler = &CH_handler_agpl
+ .handler = &CH_handler_spa,
},
{
- .url = "/main.css",
+ .url = "/agpl",
.method = MHD_HTTP_METHOD_GET,
- .handler = &CH_handler_main_css
+ .handler = &CH_handler_agpl
},
{
.url = "/config",
@@ -548,18 +548,20 @@ run (void *cls,
(void) cfgfile;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting challenger-httpd\n");
- if (GNUNET_OK !=
- TALER_TEMPLATING_init ("."))
- {
- GNUNET_break (0);
- return;
- }
go = TALER_MHD_GO_NONE;
if (CH_challenger_connection_close)
go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
TALER_MHD_setup (go);
if (GNUNET_OK !=
+ CH_spa_init ())
+ {
+ global_ret = EXIT_NOTCONFIGURED;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (config,
"CHALLENGER",
"VALIDATION_DURATION",
diff --git a/src/challenger/challenger-httpd_main_css.c b/src/challenger/challenger-httpd_main_css.c
@@ -1,92 +0,0 @@
-/*
- This file is part of Challenger
- Copyright (C) 2023 Taler Systems SA
-
- Challenger 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 3, or (at your option) any later version.
-
- Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY 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
- Challenger; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file challenger/challenger-httpd_main_css.c
- * @brief handler for /main.css
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "challenger-httpd_main_css.h"
-#include <taler/taler_mhd_lib.h>
-
-
-MHD_RESULT
-CH_handler_main_css (struct CH_HandlerContext *hc,
- const char *upload_data,
- size_t *upload_data_size)
-{
- static struct MHD_Response *reply;
-
- if (NULL == reply)
- {
- char *fn;
- struct stat sb;
- int fd;
- char *path;
-
- path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
- if (NULL == path)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- GNUNET_asprintf (&fn,
- "%s/templates/main.css",
- path);
- GNUNET_free (path);
- fd = open (fn,
- O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- fn);
- GNUNET_free (fn);
- return GNUNET_SYSERR;
- }
- if (0 !=
- fstat (fd,
- &sb))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "fstat",
- fn);
- GNUNET_break (0 == close (fd));
- GNUNET_free (fn);
- return GNUNET_OK;
- }
- GNUNET_free (fn);
- reply = MHD_create_response_from_fd (sb.st_size,
- fd);
- TALER_MHD_add_global_headers (reply);
- GNUNET_break (MHD_NO !=
- MHD_add_response_header (reply,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/css"));
- }
- if (NULL == reply)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- return MHD_queue_response (
- hc->connection,
- MHD_HTTP_OK,
- reply);
-}
-
-
-/* end of challenger-httpd_main_css.c */
diff --git a/src/challenger/challenger-httpd_main_css.h b/src/challenger/challenger-httpd_main_css.h
@@ -1,41 +0,0 @@
-/*
- This file is part of Challenger
- Copyright (C) 2023 Taler Systems SA
-
- Challenger 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 3, or (at your option) any later version.
-
- Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY 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
- Challenger; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file challenger/challenger-httpd_main_css.h
- * @brief headers for /main_css handler
- * @author Christian Grothoff
- */
-#ifndef CHALLENGER_HTTPD_MAIN_CSS_H
-#define CHALLENGER_HTTPD_MAIN_CSS_H
-#include <microhttpd.h>
-#include "challenger-httpd.h"
-
-/**
- * Manages a GET /main.css request.
- *
- * @param[in,out] hc context of the connection
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-MHD_RESULT
-CH_handler_main_css (struct CH_HandlerContext *hc,
- const char *upload_data,
- size_t *upload_data_size);
-
-#endif
-
-/* end of challenger-httpd_main_css.h */
diff --git a/src/challenger/challenger-httpd_spa.c b/src/challenger/challenger-httpd_spa.c
@@ -0,0 +1,416 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020, 2023 Taler Systems SA
+
+ Challenger 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.
+
+ Challenger 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
+ Challenger; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file challenger-httpd_spa.c
+ * @brief logic to load the single page app (/)
+ * @author Sebastian Marchano
+ * @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 "challenger-httpd_spa.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
+CH_handler_spa (struct CH_HandlerContext *hc,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct WebuiFile *w = NULL;
+ const char *infix = hc->path;
+
+ 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 (hc->connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+ hc->path);
+ if ( (MHD_YES ==
+ TALER_MHD_can_compress (hc->connection)) &&
+ (NULL != w->zspa) )
+ return MHD_queue_response (hc->connection,
+ MHD_HTTP_OK,
+ w->zspa);
+ return MHD_queue_response (hc->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
+CH_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,
+ "%sspa/",
+ 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);
+ }
+}
+
+
+/**
+ * Generates the response for "/", redirecting the
+ * client to the "/webui/" from where we serve the SPA.
+ *
+ * @param rh request handler
+ * @param connection MHD connection
+ * @param hc handler context
+ * @return MHD result code
+ */
+MHD_RESULT
+CH_spa_redirect (struct CH_HandlerContext *hc,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ 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 (hc->connection,
+ MHD_HTTP_FOUND,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+ }
+}
diff --git a/src/challenger/challenger-httpd_spa.h b/src/challenger/challenger-httpd_spa.h
@@ -0,0 +1,66 @@
+/*
+ This file is part of Challenger
+ Copyright (C) 2023 Taler Systems SA
+
+ Challenger 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 3, or (at your option) any later version.
+
+ Challenger is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY 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
+ Challenger; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file challenger-httpd_spa.h
+ * @brief logic to preload and serve static files
+ * @author Sebastian Marchano
+ * @author Christian Grothoff
+ */
+#ifndef CHALLENGER_HTTPD_SPA_H
+#define CHALLENGER_HTTPD_SPA_H
+#include <microhttpd.h>
+#include "challenger-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
+CH_handler_spa (struct CH_HandlerContext *hc,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+
+/**
+ * Preload and compress SPA files.
+ *
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+CH_spa_init (void);
+
+
+/**
+ * Generates the response for "/", redirecting the
+ * client to the "/webui/" from where we serve the SPA.
+ *
+ * @param rh request handler
+ * @param connection MHD connection
+ * @param hc handler context
+ * @return MHD result code
+ */
+MHD_RESULT
+CH_spa_redirect (struct CH_HandlerContext *hc,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+#endif
+
+/* end of challenger-httpd_spa.h */