commit e326aba94adbc5556b8ea41549856625c2390a9a
parent b65481ad8fae5fe7fad9cb0253449fdc80bf7ff8
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 3 Jun 2024 17:20:38 +0200
-implement new AML/SPA handlers
Diffstat:
4 files changed, 95 insertions(+), 302 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -1820,9 +1820,16 @@ handle_mhd_request (void *cls,
.nargs = 2
},
{
- .url = "webui",
+ .url = "aml-spa",
.method = MHD_HTTP_METHOD_GET,
- .handler.get = &TEH_handler_spa,
+ .handler.get = &TEH_handler_aml_spa,
+ .nargs = 1,
+ .nargs_is_upper_bound = true
+ },
+ {
+ .url = "kyc-spa",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler.get = &TEH_handler_kyc_spa,
.nargs = 1,
.nargs_is_upper_bound = true
},
diff --git a/src/exchange/taler-exchange-httpd_spa.c b/src/exchange/taler-exchange-httpd_spa.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020, 2023 Taler Systems SA
+ Copyright (C) 2020, 2023, 2024 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
@@ -27,308 +27,68 @@
/**
- * Resource from the WebUi.
+ * Resources of the AML SPA.
*/
-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 WebUI, kept in a DLL.
- */
-static struct WebuiFile *webui_head;
+static struct TALER_MHD_Spa *aml_spa;
/**
- * Resources of the WebUI, kept in a DLL.
+ * Resources of the KYC SPA.
*/
-static struct WebuiFile *webui_tail;
+static struct TALER_MHD_Spa *kyc_spa;
MHD_RESULT
-TEH_handler_spa (struct TEH_RequestContext *rc,
- const char *const args[])
+TEH_handler_aml_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;
- }
-
+ const char *path = args[0];
+ struct TALER_AccountAccessTokenP tok;
+
+ if (GNUNET_OK ==
+ GNUNET_STRINGS_string_to_data (path,
+ strlen (path),
+ &tok,
+ sizeof (tok)))
{
- 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);
- }
+ /* The access token is used internally by the SPA,
+ we simply map all access tokens to "index.html" */
+ path = "index.html";
}
+ return TALER_MHD_spa_handler (aml_spa,
+ rc->connection,
+ path);
+}
- 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;
+MHD_RESULT
+TEH_handler_kyc_spa (struct TEH_RequestContext *rc,
+ const char *const args[])
+{
+ const char *path = args[0];
- 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;
+ return TALER_MHD_spa_handler (kyc_spa,
+ rc->connection,
+ path);
}
enum GNUNET_GenericReturnValue
TEH_spa_init ()
{
- char *dn;
-
+ aml_spa = TALER_MHD_spa_load ("exchange/aml-spa/");
+ if (NULL == aml_spa)
{
- 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/aml-spa/",
- path);
- GNUNET_free (path);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
-
- if (-1 ==
- GNUNET_DISK_directory_scan (dn,
- &build_webui,
- NULL))
+ kyc_spa = TALER_MHD_spa_load ("exchange/kyc-spa/");
+ if (NULL == kyc_spa)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load WebUI from `%s'\n",
- dn);
- GNUNET_free (dn);
+ GNUNET_break (0);
+ TALER_MHD_spa_free (aml_spa);
+ aml_spa = NULL;
return GNUNET_SYSERR;
}
- GNUNET_free (dn);
return GNUNET_OK;
}
@@ -339,24 +99,14 @@ TEH_spa_init ()
void __attribute__ ((destructor))
get_spa_fini ()
{
- struct WebuiFile *w;
-
- while (NULL != (w = webui_head))
+ if (NULL != kyc_spa)
+ {
+ TALER_MHD_spa_free (kyc_spa);
+ kyc_spa = NULL;
+ }
+ if (NULL != aml_spa)
{
- 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);
+ TALER_MHD_spa_free (aml_spa);
+ aml_spa = NULL;
}
}
diff --git a/src/exchange/taler-exchange-httpd_spa.h b/src/exchange/taler-exchange-httpd_spa.h
@@ -26,15 +26,29 @@
/**
- * Return our single-page-app user interface (see contrib/wallet-core/).
+ * Return our single-page-app user interface
+ * for AML staff (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[]);
+TEH_handler_aml_spa (struct TEH_RequestContext *rc,
+ const char *const args[]);
+
+
+/**
+ * Return our single-page-app user interface
+ * for the KYC process (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_kyc_spa (struct TEH_RequestContext *rc,
+ const char *const args[]);
/**
diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h
@@ -984,12 +984,34 @@ MHD_RESULT
TALER_MHD_reply_cors_preflight (struct MHD_Connection *connection);
+/**
+ * Load SPA files from @a dir
+ *
+ * @param dir directory suffix to append to our data directory with the location of the files of the SPA
+ * @return handle to serve static files from @a dir
+ */
struct TALER_MHD_Spa *
TALER_MHD_spa_load (const char *dir);
+
+/**
+ * Release resources used by SPA handler.
+ *
+ * @param[in] spa data structure to release
+ */
void
TALER_MHD_spa_free (struct TALER_MHD_Spa *spa);
+
+/**
+ * Handle HTTP request for files in a @a spa. Generates
+ * a 404 if no file at @a path does exists.
+ *
+ * @param spa the SPA to serve files from
+ * @param connection HTTP connection to return data on
+ * @param path request path to match against the @a spa
+ * @return MHD status code to give to MHD
+ */
MHD_RESULT
TALER_MHD_spa_handler (const struct TALER_MHD_Spa *spa,
struct MHD_Connection *connection,