aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbootstrap19
-rw-r--r--contrib/Makefile.am.in19
-rw-r--r--debian/taler-auditor.install3
-rw-r--r--debian/taler-exchange.install3
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-info.c641
-rw-r--r--src/exchange/taler-exchange-httpd_spa.c8
6 files changed, 675 insertions, 18 deletions
diff --git a/bootstrap b/bootstrap
index 5c6fab802..9a3305bca 100755
--- a/bootstrap
+++ b/bootstrap
@@ -40,9 +40,26 @@ fi
# Generate Makefile.am in contrib/
cd contrib
rm -f Makefile.am
-find wallet-core/aml-backoffice/ -type f | sort | awk '{print " " $1 " \\" }' > Makefile.am.ext
+echo 'dist_amlspapkgdata_DATA = \' > Makefile.am.ext
+find wallet-core/aml-backoffice/ -type f | sort | awk '{print " " $1 " \\" }' >> Makefile.am.ext
# Remove extra '\' at the end of the file
truncate -s -2 Makefile.am.ext
+
+echo "" >> Makefile.am.ext
+echo 'dist_kycspapkgdata_DATA = \' >> Makefile.am.ext
+# FIXME: replace aml-backoffice with kyc-ui once ready!
+find wallet-core/aml-backoffice/ -type f | sort | awk '{print " " $1 " \\" }' >> Makefile.am.ext
+# Remove extra '\' at the end of the file
+truncate -s -2 Makefile.am.ext
+
+echo "" >> Makefile.am.ext
+echo 'dist_auditorspapkgdata_DATA = \' >> Makefile.am.ext
+# FIXME: replace aml-backoffice with auditor-backoffice once ready!
+find wallet-core/auditor-backoffice/ -type f | sort | awk '{print " " $1 " \\" }' >> 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
diff --git a/contrib/Makefile.am.in b/contrib/Makefile.am.in
index d3cfa769c..c6c59357c 100644
--- a/contrib/Makefile.am.in
+++ b/contrib/Makefile.am.in
@@ -37,10 +37,6 @@ install-exec-local:
mkdir -p $(DESTDIR)$(datadir)
cp --parents -r $$(find locale/ -name "*.po") $(DESTDIR)$(datadir)
-rdatadir=$(datadir)/taler/exchange
-rdata_DATA = \
- auditor-report.tex.j2
-
bin_SCRIPTS = \
taler-auditor-dbconfig \
taler-exchange-dbconfig \
@@ -60,10 +56,13 @@ EXTRA_DIST = \
microhttpd.tag \
packages
-spapkgdatadir = $(prefix)/share/taler/exchange/spa/
+# These are for the various single-page-apps
+# imported from the wallet-core.git
+# prebuilt branch. These MUST be present, they will
+# be used by code generated by 'bootstrap'!
+
+amlspapkgdatadir = $(prefix)/share/taler/exchange/aml-spa/
+
+auditorspapkgdatadir = $(prefix)/share/taler/auditor/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 = \
+kycspapkgdatadir = $(prefix)/share/taler/exchange/kyc-spa/
diff --git a/debian/taler-auditor.install b/debian/taler-auditor.install
index 4f3d5a1b2..aa69db519 100644
--- a/debian/taler-auditor.install
+++ b/debian/taler-auditor.install
@@ -17,8 +17,7 @@ usr/share/info/taler-auditor*
usr/share/taler/config.d/auditor*
usr/share/taler/sql/auditor/*
+usr/share/taler/auditor/spa/*
# Configuration
debian/etc-taler-auditor/* etc/
-
-usr/share/taler/exchange/auditor-report.tex.j2
diff --git a/debian/taler-exchange.install b/debian/taler-exchange.install
index f8fef2c3b..93cf8b054 100644
--- a/debian/taler-exchange.install
+++ b/debian/taler-exchange.install
@@ -34,7 +34,8 @@ usr/share/man/man1/taler-exchange-wirewatch*
usr/share/info/taler-exchange*
usr/share/taler/config.d/*
usr/share/taler/exchange/templates/*.must
-usr/share/taler/exchange/spa/*
+usr/share/taler/exchange/aml-spa/*
+usr/share/taler/exchange/kyc-spa/*
# configuration files in /etc/taler
debian/etc-taler-exchange/* etc/
diff --git a/src/exchange/taler-exchange-httpd_kyc-info.c b/src/exchange/taler-exchange-httpd_kyc-info.c
new file mode 100644
index 000000000..974d3b84f
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-info.c
@@ -0,0 +1,641 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Affero 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 MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-info.c
+ * @brief Handle request for generic KYC info.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_kyclogic_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler_signatures.h"
+#include "taler_dbevents.h"
+#include "taler-exchange-httpd_keys.h"
+#include "taler-exchange-httpd_kyc-wallet.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Reserve GET request that is long-polling.
+ */
+struct KycPoller
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct KycPoller *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct KycPoller *prev;
+
+ /**
+ * Connection we are handling.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Logic for @e ih
+ */
+ struct TALER_KYCLOGIC_Plugin *ih_logic;
+
+ /**
+ * Handle to asynchronously running KYC initiation
+ * request.
+ */
+ struct TALER_KYCLOGIC_InitiateHandle *ih;
+
+ /**
+ * Subscription for the database event we are
+ * waiting for.
+ */
+ struct GNUNET_DB_EventHandler *eh;
+
+ /**
+ * Row of the requirement being infoed.
+ */
+ uint64_t requirement_row;
+
+ /**
+ * Row of KYC process being initiated.
+ */
+ uint64_t process_row;
+
+ /**
+ * Hash of the payto:// URI we are confirming to
+ * have finished the KYC for.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * When will this request time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Public limits that apply to the account,
+ * if @e have_token is true.
+ * NULL if no limits are public.
+ */
+ json_t *limits;
+
+ /**
+ * Set to access token for a KYC process by the account,
+ * if @e have_token is true.
+ */
+ struct TALER_AccountAccessTokenP access_token;
+
+ /**
+ * Signature by the account owner authorizing this
+ * operation.
+ */
+ union TALER_AccountSignatureP account_sig;
+
+ /**
+ * Set to error details, on error (@ec not TALER_EC_NONE).
+ */
+ char *hint;
+
+ /**
+ * Set to error encountered with KYC logic, if any.
+ */
+ enum TALER_ErrorCode ec;
+
+ /**
+ * True if account is under AML review and this is
+ * exposed.
+ */
+ bool aml_review;
+
+ /**
+ * True if @e access_token was initialized.
+ */
+ bool have_token;
+
+ /**
+ * True if we are still suspended.
+ */
+ bool suspended;
+
+ /**
+ * False if KYC is not required.
+ */
+ bool kyc_required;
+
+ /**
+ * True if we once tried the KYC initiation.
+ */
+ bool ih_done;
+
+};
+
+
+/**
+ * Head of list of requests in long polling.
+ */
+static struct KycPoller *kyp_head;
+
+/**
+ * Tail of list of requests in long polling.
+ */
+static struct KycPoller *kyp_tail;
+
+
+void
+TEH_kyc_info_cleanup ()
+{
+ struct KycPoller *kyp;
+
+ while (NULL != (kyp = kyp_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (kyp_head,
+ kyp_tail,
+ kyp);
+ if (NULL != kyp->ih)
+ {
+ kyp->ih_logic->initiate_cancel (kyp->ih);
+ kyp->ih = NULL;
+ }
+ if (kyp->suspended)
+ {
+ kyp->suspended = false;
+ MHD_resume_connection (kyp->connection);
+ }
+ }
+}
+
+
+/**
+ * Function called once a connection is done to
+ * clean up the `struct ReservePoller` state.
+ *
+ * @param rc context to clean up for
+ */
+static void
+kyp_cleanup (struct TEH_RequestContext *rc)
+{
+ struct KycPoller *kyp = rc->rh_ctx;
+
+ GNUNET_assert (! kyp->suspended);
+ if (NULL != kyp->eh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Cancelling DB event listening\n");
+ TEH_plugin->event_listen_cancel (TEH_plugin->cls,
+ kyp->eh);
+ kyp->eh = NULL;
+ }
+ if (NULL != kyp->ih)
+ {
+ kyp->ih_logic->initiate_cancel (kyp->ih);
+ kyp->ih = NULL;
+ }
+ json_decref (kyp->kyc_details);
+ GNUNET_free (kyp->kyc_url);
+ GNUNET_free (kyp->hint);
+ GNUNET_free (kyp);
+}
+
+
+#if FIXME
+/**
+ * Function called with the result of a KYC initiation
+ * operation.
+ *
+ * @param cls closure with our `struct KycPoller *`
+ * @param ec #TALER_EC_NONE on success
+ * @param redirect_url set to where to redirect the user on success, NULL on failure
+ * @param provider_user_id set to user ID at the provider, or NULL if not supported or unknown
+ * @param provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
+ * @param error_msg_hint set to additional details to return to user, NULL on success
+ */
+static void
+initiate_cb (
+ void *cls,
+ enum TALER_ErrorCode ec,
+ const char *redirect_url,
+ const char *provider_user_id,
+ const char *provider_legitimization_id,
+ const char *error_msg_hint)
+{
+ struct KycPoller *kyp = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ kyp->ih = NULL;
+ kyp->ih_done = true;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC initiation `%s' completed with ec=%d (%s)\n",
+ provider_legitimization_id,
+ ec,
+ (TALER_EC_NONE == ec)
+ ? redirect_url
+ : error_msg_hint);
+ kyp->ec = ec;
+ if (TALER_EC_NONE == ec)
+ {
+ kyp->kyc_url = GNUNET_strdup (redirect_url);
+ }
+ else
+ {
+ kyp->hint = GNUNET_strdup (error_msg_hint);
+ }
+ qs = TEH_plugin->update_kyc_process_by_row (
+ TEH_plugin->cls,
+ kyp->process_row,
+ kyp->section_name,
+ &kyp->h_payto,
+ provider_user_id,
+ provider_legitimization_id,
+ redirect_url,
+ GNUNET_TIME_UNIT_ZERO_ABS);
+ if (qs <= 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "KYC requirement update failed for %s with status %d at %s:%u\n",
+ TALER_B2S (&kyp->h_payto),
+ qs,
+ __FILE__,
+ __LINE__);
+ GNUNET_assert (kyp->suspended);
+ kyp->suspended = false;
+ GNUNET_CONTAINER_DLL_remove (kyp_head,
+ kyp_tail,
+ kyp);
+ MHD_resume_connection (kyp->connection);
+ TALER_MHD_daemon_trigger ();
+}
+
+
+#endif
+
+
+/**
+ * Function implementing database transaction to info wallet's KYC status.
+ * Runs the transaction logic; IF it returns a non-error code, the transaction
+ * logic MUST NOT queue a MHD response. IF it returns an hard error, the
+ * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it
+ * returns the soft error code, the function MAY be called again to retry and
+ * MUST not queue a MHD response.
+ *
+ * @param cls closure with a `struct KycPoller *`
+ * @param connection MHD request which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+kyc_info (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+#if FIXME
+ struct KycPoller *kyp = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_KYCLOGIC_ProviderDetails *pd;
+ enum GNUNET_GenericReturnValue ret;
+ struct TALER_PaytoHashP h_payto;
+ char *requirements;
+ char *redirect_url;
+ bool satisfied;
+
+ qs = TEH_plugin->lookup_kyc_requirement_by_row (
+ TEH_plugin->cls,
+ kyp->requirement_row,
+ &requirements,
+ &h_payto);
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No KYC requirements open for %llu\n",
+ (unsigned long long) kyp->requirement_row);
+ return qs;
+ }
+ if (qs < 0)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
+ return qs;
+ }
+ if (0 !=
+ GNUNET_memcmp (&kyp->h_payto,
+ &h_payto))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Requirement %llu provided, but h_payto does not match\n",
+ (unsigned long long) kyp->requirement_row);
+ GNUNET_break_op (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_EXCHANGE_KYC_INFO_AUTHORIZATION_FAILED,
+ "h_payto");
+ GNUNET_free (requirements);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ qs = TALER_KYCLOGIC_info_satisfied (
+ &requirements,
+ &h_payto,
+ &kyp->kyc_details,
+ TEH_plugin->select_satisfied_kyc_processes,
+ TEH_plugin->cls,
+ &satisfied);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "kyc_test_required");
+ GNUNET_free (requirements);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (satisfied)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC requirements `%s' already satisfied\n",
+ requirements);
+ GNUNET_free (requirements);
+ return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
+ }
+
+ kyp->kyc_required = true;
+ ret = TALER_KYCLOGIC_requirements_to_logic (requirements,
+ &kyp->ih_logic,
+ &pd,
+ &kyp->section_name);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "KYC requirements `%s' cannot be infoed, but are set as required in database!\n",
+ requirements);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_GONE,
+ requirements);
+ GNUNET_free (requirements);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ GNUNET_free (requirements);
+
+ if (kyp->ih_done)
+ return qs;
+ qs = TEH_plugin->get_pending_kyc_requirement_process (
+ TEH_plugin->cls,
+ &h_payto,
+ kyp->section_name,
+ &redirect_url);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "insert_kyc_requirement_process");
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if ( (qs > 0) &&
+ (NULL != redirect_url) )
+ {
+ kyp->kyc_url = redirect_url;
+ return qs;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ /* set up new requirement process */
+ qs = TEH_plugin->insert_kyc_requirement_process (
+ TEH_plugin->cls,
+ &h_payto,
+ kyp->section_name,
+ NULL,
+ NULL,
+ &kyp->process_row);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_STORE_FAILED,
+ "insert_kyc_requirement_process");
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Initiating KYC info with logic %s\n",
+ kyp->ih_logic->name);
+ kyp->ih = kyp->ih_logic->initiate (kyp->ih_logic->cls,
+ pd,
+ &h_payto,
+ kyp->process_row,
+ &initiate_cb,
+ kyp);
+ GNUNET_break (NULL != kyp->ih);
+ return qs;
+#else
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+#endif
+}
+
+
+/**
+ * Function called on events received from Postgres.
+ * Wakes up long pollers.
+ *
+ * @param cls the `struct TEH_RequestContext *`
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
+ */
+static void
+db_event_cb (void *cls,
+ const void *extra,
+ size_t extra_size)
+{
+ struct TEH_RequestContext *rc = cls;
+ struct KycPoller *kyp = rc->rh_ctx;
+ struct GNUNET_AsyncScopeSave old_scope;
+
+ (void) extra;
+ (void) extra_size;
+ if (! kyp->suspended)
+ return; /* event triggered while main transaction
+ was still running, or got multiple wake-up events */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received KYC update event\n");
+ kyp->suspended = false;
+ GNUNET_async_scope_enter (&rc->async_scope_id,
+ &old_scope);
+ TEH_info_invariants ();
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Resuming from long-polling on KYC status\n");
+ GNUNET_CONTAINER_DLL_remove (kyp_head,
+ kyp_tail,
+ kyp);
+ MHD_resume_connection (kyp->connection);
+ TALER_MHD_daemon_trigger ();
+ TEH_info_invariants ();
+ GNUNET_async_scope_restore (&old_scope);
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_info (
+ struct TEH_RequestContext *rc,
+ const char *const args[1])
+{
+ struct KycPoller *kyp = rc->rh_ctx;
+ MHD_RESULT res;
+ enum GNUNET_GenericReturnValue ret;
+
+ if (NULL == kyp)
+ {
+ kyp = GNUNET_new (struct KycPoller);
+ kyp->connection = rc->connection;
+ rc->rh_ctx = kyp;
+ rc->rh_cleaner = &kyp_cleanup;
+
+ {
+ unsigned long long requirement_row;
+ char dummy;
+
+ if (1 !=
+ sscanf (args[0],
+ "%llu%c",
+ &requirement_row,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "requirement_row");
+ }
+ kyp->requirement_row = (uint64_t) requirement_row;
+ }
+ TALER_MHD_parse_request_timeout (rc->connection,
+ &kyp->timeout);
+ }
+
+ if ( (NULL == kyp->eh) &&
+ GNUNET_TIME_absolute_is_future (kyp->timeout) )
+ {
+ struct TALER_KycCompletedEventP rep = {
+ .header.size = htons (sizeof (rep)),
+ .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
+ .h_payto = kyp->h_payto
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting DB event listening\n");
+ kyp->eh = TEH_plugin->event_listen (
+ TEH_plugin->cls,
+ GNUNET_TIME_absolute_get_remaining (kyp->timeout),
+ &rep.header,
+ &db_event_cb,
+ rc);
+ }
+
+ ret = TEH_DB_run_transaction (rc->connection,
+ "kyc info",
+ TEH_MT_REQUEST_OTHER,
+ &res,
+ &kyc_info,
+ kyp);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Transaction failed.\n");
+ return res;
+ }
+
+ if (TALER_EC_NONE != kyp->ec)
+ {
+ return TALER_MHD_reply_with_ec (rc->connection,
+ kyp->ec,
+ kyp->hint);
+ }
+
+ if (NULL != kyp->ih)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending HTTP request on KYC logic...\n");
+ kyp->suspended = true;
+ GNUNET_CONTAINER_DLL_insert (kyp_head,
+ kyp_tail,
+ kyp);
+ MHD_suspend_connection (kyp->connection);
+ return MHD_YES;
+ }
+
+ /* long polling for positive result? */
+ if ( (kyp->kyc_required) &&
+ GNUNET_TIME_absolute_is_future (kyp->timeout))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending HTTP request on timeout (%s) now...\n",
+ GNUNET_TIME_relative2s (GNUNET_TIME_absolute_get_remaining (
+ kyp->timeout),
+ true));
+ GNUNET_assert (NULL != kyp->eh);
+ kyp->suspended = true;
+ kyp->section_name = NULL;
+ GNUNET_CONTAINER_DLL_insert (kyp_head,
+ kyp_tail,
+ kyp);
+ MHD_suspend_connection (kyp->connection);
+ return MHD_YES;
+ }
+
+ /* KYC plugin generated reply? */
+ if (kyp->have_token)
+ {
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ kyp->kyc_required
+ ? MHD_HTTP_ACCEPTED
+ : MHD_HTTP_OK,
+ GNUNET_JSON_pack_bool ("aml_review",
+ kyp->aml_review),
+ GNUNET_JSON_pack_data_auto ("access_token",
+ &kyp->access_token),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_array_steal ("limits",
+ kyp->limits)));
+ }
+
+ /* KYC not required */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC not required %llu\n",
+ (unsigned long long) kyp->requirement_row);
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+}
+
+
+/* end of taler-exchange-httpd_kyc-info.c */
diff --git a/src/exchange/taler-exchange-httpd_spa.c b/src/exchange/taler-exchange-httpd_spa.c
index 60bed3d28..e6b672c16 100644
--- a/src/exchange/taler-exchange-httpd_spa.c
+++ b/src/exchange/taler-exchange-httpd_spa.c
@@ -15,7 +15,7 @@
*/
/**
* @file taler-exchange-httpd_spa.c
- * @brief logic to load the single page app (/)
+ * @brief logic to load single page apps (/)
* @author Christian Grothoff
*/
#include "platform.h"
@@ -60,12 +60,12 @@ struct WebuiFile
/**
- * Resources of the WebuUI, kept in a DLL.
+ * Resources of the WebUI, kept in a DLL.
*/
static struct WebuiFile *webui_head;
/**
- * Resources of the WebuUI, kept in a DLL.
+ * Resources of the WebUI, kept in a DLL.
*/
static struct WebuiFile *webui_tail;
@@ -312,7 +312,7 @@ TEH_spa_init ()
return GNUNET_SYSERR;
}
GNUNET_asprintf (&dn,
- "%sexchange/spa/",
+ "%sexchange/aml-spa/",
path);
GNUNET_free (path);
}