summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_kyc-check.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-httpd_kyc-check.c')
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-check.c701
1 files changed, 602 insertions, 99 deletions
diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c
index ae1ab34f2..362c20a2e 100644
--- a/src/exchange/taler-exchange-httpd_kyc-check.c
+++ b/src/exchange/taler-exchange-httpd_kyc-check.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2021 Taler Systems SA
+ 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
@@ -25,37 +25,261 @@
#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"
/**
- * Context for the request.
+ * Reserve GET request that is long-polling.
*/
-struct KycCheckContext
+struct KycPoller
{
/**
- * UUID being checked.
+ * Kept in a DLL.
*/
- uint64_t payment_target_uuid;
+ struct KycPoller *next;
/**
- * Current KYC status.
+ * Kept in a DLL.
*/
- struct TALER_EXCHANGEDB_KycStatus kyc;
+ 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 checked.
+ */
+ 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 GNUNET_HashCode h_payto;
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * When will this request time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * If the KYC complete, what kind of data was collected?
+ */
+ json_t *kyc_details;
+
+ /**
+ * Set to starting URL of KYC process if KYC is required.
+ */
+ char *kyc_url;
+
+ /**
+ * Set to error details, on error (@ec not TALER_EC_NONE).
+ */
+ char *hint;
+
+ /**
+ * Name of the section of the provider in the configuration.
+ */
+ const char *section_name;
+
+ /**
+ * Set to AML status of the account.
+ */
+ enum TALER_AmlDecisionState aml_status;
+
+ /**
+ * Set to error encountered with KYC logic, if any.
+ */
+ enum TALER_ErrorCode ec;
+
+ /**
+ * What kind of entity is doing the KYC check?
+ */
+ enum TALER_KYCLOGIC_KycUserType ut;
+
+ /**
+ * 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_check_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);
+}
+
+
+/**
+ * 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 ();
+}
+
+
+/**
* Function implementing database transaction to check 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
@@ -63,7 +287,7 @@ struct KycCheckContext
* 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 KycCheckContext *`
+ * @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 (!)
@@ -74,13 +298,55 @@ kyc_check (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
- struct KycCheckContext *kcc = cls;
+ 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->select_kyc_status (TEH_plugin->cls,
- kcc->payment_target_uuid,
- &kcc->h_payto,
- &kcc->kyc);
+ qs = TEH_plugin->lookup_kyc_requirement_by_row (
+ TEH_plugin->cls,
+ kyp->requirement_row,
+ &requirements,
+ &kyp->aml_status,
+ &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_CHECK_AUTHORIZATION_FAILED,
+ "h_payto");
+ GNUNET_free (requirements);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ qs = TALER_KYCLOGIC_check_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)
@@ -89,117 +355,354 @@ kyc_check (void *cls,
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
- "inselect_wallet_status");
+ "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->ut,
+ &kyp->ih_logic,
+ &pd,
+ &kyp->section_name);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "KYC requirements `%s' cannot be checked, 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 check 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;
}
+/**
+ * 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_check_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_check_invariants ();
+ GNUNET_async_scope_restore (&old_scope);
+}
+
+
MHD_RESULT
TEH_handler_kyc_check (
struct TEH_RequestContext *rc,
- const char *const args[])
+ const char *const args[3])
{
- unsigned long long payment_target_uuid;
+ struct KycPoller *kyp = rc->rh_ctx;
MHD_RESULT res;
enum GNUNET_GenericReturnValue ret;
- char dummy;
+ struct GNUNET_TIME_Timestamp now;
- if (1 !=
- sscanf (args[0],
- "%llu%c",
- &payment_target_uuid,
- &dummy))
+ if (NULL == kyp)
{
- GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (rc->connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "payment_target_uuid");
+ 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;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (args[1],
+ strlen (args[1]),
+ &kyp->h_payto,
+ sizeof (kyp->h_payto)))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "h_payto");
+ }
+
+ if (GNUNET_OK !=
+ TALER_KYCLOGIC_kyc_user_type_from_string (args[2],
+ &kyp->ut))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "usertype");
+ }
+
+ TALER_MHD_parse_request_timeout (rc->connection,
+ &kyp->timeout);
+ }
+ /* KYC plugin generated reply? */
+ if (NULL != kyp->kyc_url)
+ {
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_ACCEPTED,
+ GNUNET_JSON_pack_uint64 ("aml_status",
+ kyp->aml_status),
+ GNUNET_JSON_pack_string ("kyc_url",
+ kyp->kyc_url));
}
- if (TEH_KYC_NONE == TEH_kyc_config.mode)
+ 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);
+ }
+
+ now = GNUNET_TIME_timestamp_get ();
+ ret = TEH_DB_run_transaction (rc->connection,
+ "kyc check",
+ TEH_MT_REQUEST_OTHER,
+ &res,
+ &kyc_check,
+ kyp);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Transaction failed.\n");
+ return res;
+ }
+ /* KYC plugin generated reply? */
+ if (NULL != kyp->kyc_url)
+ {
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_ACCEPTED,
+ GNUNET_JSON_pack_uint64 ("aml_status",
+ kyp->aml_status),
+ GNUNET_JSON_pack_string ("kyc_url",
+ kyp->kyc_url));
+ }
+
+ if ( (NULL == kyp->ih) &&
+ (! kyp->kyc_required) )
+ {
+ if (TALER_AML_NORMAL != kyp->aml_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "KYC is OK, but AML active: %d\n",
+ (int) kyp->aml_status);
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
+ GNUNET_JSON_pack_uint64 ("aml_status",
+ kyp->aml_status));
+ }
+ /* 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);
+ }
+
+ if (NULL != kyp->ih)
{
- struct GNUNET_TIME_Absolute now;
- struct KycCheckContext kcc = {
- .payment_target_uuid = payment_target_uuid
- };
+ 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;
+ }
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
- ret = TEH_DB_run_transaction (rc->connection,
- "kyc check",
- &res,
- &kyc_check,
- &kcc);
- if (GNUNET_SYSERR == ret)
- return res;
- if (! kcc.kyc.ok)
- {
- char *url;
- char *redirect_uri;
- char *redirect_uri_encoded;
-
- GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode);
- GNUNET_asprintf (&redirect_uri,
- "%s/kyc-proof/%llu",
- TEH_base_url,
- payment_target_uuid);
- redirect_uri_encoded = TALER_urlencode (redirect_uri);
- GNUNET_free (redirect_uri);
- GNUNET_asprintf (&url,
- "%s/login?client_id=%s&redirect_uri=%s",
- TEH_kyc_config.details.oauth2.url,
- TEH_kyc_config.details.oauth2.client_id,
- redirect_uri_encoded);
- GNUNET_free (redirect_uri_encoded);
-
- res = TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_ACCEPTED,
- GNUNET_JSON_pack_string ("kyc_url",
- url));
- GNUNET_free (url);
- return res;
- }
+ /* long polling? */
+ if ( (NULL != kyp->section_name) &&
+ 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;
+ }
+
+ if (TALER_EC_NONE != kyp->ec)
+ {
+ return TALER_MHD_reply_with_ec (rc->connection,
+ kyp->ec,
+ kyp->hint);
+ }
+
+ /* KYC must have succeeded! */
+ {
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+ enum TALER_ErrorCode ec;
+
+ if (TALER_EC_NONE !=
+ (ec = TALER_exchange_online_account_setup_success_sign (
+ &TEH_keys_exchange_sign_,
+ &kyp->h_payto,
+ kyp->kyc_details,
+ now,
+ &pub,
+ &sig)))
{
- struct TALER_ExchangePublicKeyP pub;
- struct TALER_ExchangeSignatureP sig;
- struct TALER_ExchangeAccountSetupSuccessPS as = {
- .purpose.purpose = htonl (
- TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
- .purpose.size = htonl (sizeof (as)),
- .h_payto = kcc.h_payto,
- .timestamp = GNUNET_TIME_absolute_hton (now)
- };
- enum TALER_ErrorCode ec;
-
- if (TALER_EC_NONE !=
- (ec = TEH_keys_exchange_sign (&as,
- &pub,
- &sig)))
- {
- return TALER_MHD_reply_with_ec (rc->connection,
- ec,
- NULL);
- }
- return TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_OK,
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &sig),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &pub),
- GNUNET_JSON_pack_time_abs ("now",
- now));
+ return TALER_MHD_reply_with_ec (rc->connection,
+ ec,
+ NULL);
}
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_data_auto ("exchange_sig",
+ &sig),
+ GNUNET_JSON_pack_data_auto ("exchange_pub",
+ &pub),
+ GNUNET_JSON_pack_uint64 ("aml_status",
+ kyp->aml_status),
+ GNUNET_JSON_pack_object_incref ("kyc_details",
+ kyp->kyc_details),
+ GNUNET_JSON_pack_timestamp ("now",
+ now));
}
}