challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

commit e74b90750c0e7f63bc9a880efbde696399abe200
parent e35a990bff113edb25a5484f7a04689c3750a43d
Author: Sebastian <sebasjm@gmail.com>
Date:   Wed,  3 Jul 2024 10:06:55 -0300

use challenger spa

Diffstat:
Mcontrib/Makefile.am.in | 10+++++-----
Msrc/challenger/Makefile.am | 2+-
Msrc/challenger/challenger-httpd.c | 26++++++++++++++------------
Dsrc/challenger/challenger-httpd_main_css.c | 92-------------------------------------------------------------------------------
Dsrc/challenger/challenger-httpd_main_css.h | 41-----------------------------------------
Asrc/challenger/challenger-httpd_spa.c | 416+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/challenger/challenger-httpd_spa.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 */