aboutsummaryrefslogtreecommitdiff
path: root/src/exchange
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2023-06-03 10:45:31 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2023-06-03 10:45:31 +0200
commit80a1b8f5240e8307e1c73862fb8810d7c2bdc874 (patch)
tree5661068ec9976aa8711dc931355f6bd87ab35fd6 /src/exchange
parent4a31a180a4595aa040060e91ccde4f839aa02f72 (diff)
parent2ea3ae1008020589b43a51663c45556a08547212 (diff)
Merge branch 'master' into age-withdraw
Diffstat (limited to 'src/exchange')
-rw-r--r--src/exchange/Makefile.am4
-rw-r--r--src/exchange/exchange.conf13
-rw-r--r--src/exchange/taler-exchange-aggregator.c6
-rw-r--r--src/exchange/taler-exchange-httpd.c38
-rw-r--r--src/exchange/taler-exchange-httpd.h10
-rw-r--r--src/exchange/taler-exchange-httpd_aml-decision-get.c3
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.c239
-rw-r--r--src/exchange/taler-exchange-httpd_common_kyc.h99
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c2
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.c112
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-webhook.c113
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_attest.c3
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_get_attest.c3
-rwxr-xr-xsrc/exchange/taler-exchange-kyc-aml-pep-trigger.sh7
-rw-r--r--src/exchange/test_taler_exchange_httpd.conf3
15 files changed, 527 insertions, 128 deletions
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 3d87a2a5..ba74a10f 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -15,6 +15,8 @@ pkgcfg_DATA = \
exchange.conf
# Programs
+bin_SCRIPTS = \
+ taler-exchange-kyc-aml-pep-trigger.sh
bin_PROGRAMS = \
taler-exchange-aggregator \
@@ -131,6 +133,7 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
taler-exchange-httpd_age-withdraw_reveal.c taler-exchange-httpd_age-withdraw_reveal.h \
taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
+ taler-exchange-httpd_common_kyc.c taler-exchange-httpd_common_kyc.h \
taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
taler-exchange-httpd_contract.c taler-exchange-httpd_contract.h \
taler-exchange-httpd_csr.c taler-exchange-httpd_csr.h \
@@ -227,4 +230,5 @@ EXTRA_DIST = \
test_taler_exchange_httpd.get \
test_taler_exchange_httpd.post \
exchange.conf \
+ $(bin_SCRIPTS) \
$(check_SCRIPTS)
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index 38e5816f..d1558a49 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -6,10 +6,23 @@
# This must be adjusted to your actual installation.
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
+# Must be set to the threshold above which transactions
+# are flagged for AML review.
+# AML_THRESHOLD =
+
+# Specifies a program (binary) to run on KYC attribute data to decide
+# whether we should immediately flag an account for AML review.
+# The KYC attribute data will be passed on standard-input.
+# Return non-zero to trigger AML review of the new user.
+KYC_AML_TRIGGER = true
+
# Attribute encryption key for storing attributes encrypted
# in the database. Should be a high-entropy nonce.
ATTRIBUTE_ENCRYPTION_KEY = SET_ME_PLEASE
+# Set to NO to disable tipping.
+ENABLE_TIPPING = YES
+
# How long do we allow /keys to be cached at most? The actual
# limit is the minimum of this value and the first expected
# significant change in /keys based on the expiration times.
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index 38110a5e..0073d85e 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -303,17 +303,17 @@ parse_aggregator_config (void)
(TALER_amount_is_zero (&currency_round_unit)) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Need non-zero amount in section `TALER' under `CURRENCY_ROUND_UNIT'\n");
+ "Need non-zero amount in section `taler' under `CURRENCY_ROUND_UNIT'\n");
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
TALER_config_get_amount (cfg,
- "taler",
+ "exchange",
"AML_THRESHOLD",
&aml_threshold))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Need amount in section `TALER' under `AML_THRESHOLD'\n");
+ "Need amount in section `exchange' under `AML_THRESHOLD'\n");
return GNUNET_SYSERR;
}
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 7e11655c..348967f7 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -154,6 +154,16 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
char *TEH_currency;
/**
+ * Name of the KYC-AML-trigger evaluation binary.
+ */
+char *TEH_kyc_aml_trigger;
+
+/**
+ * Option set to #GNUNET_YES if tipping is enabled.
+ */
+int TEH_enable_tipping;
+
+/**
* What is the largest amount we allow a peer to
* merge into a reserve before always triggering
* an AML check?
@@ -1845,6 +1855,17 @@ exchange_serve_process_config (void)
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange",
+ "KYC_AML_TRIGGER",
+ &TEH_kyc_aml_trigger))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_AML_TRIGGER");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
TALER_config_get_currency (TEH_cfg,
&TEH_currency))
{
@@ -1855,19 +1876,30 @@ exchange_serve_process_config (void)
}
if (GNUNET_OK !=
TALER_config_get_amount (TEH_cfg,
- "taler",
+ "exchange",
"AML_THRESHOLD",
&TEH_aml_threshold))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Need amount in section `TALER' under `AML_THRESHOLD'\n");
+ "Need amount in section `exchange' under `AML_THRESHOLD'\n");
return GNUNET_SYSERR;
}
if (0 != strcmp (TEH_currency,
TEH_aml_threshold.currency))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Amount in section `TALER' under `AML_THRESHOLD' uses the wrong currency!\n");
+ "Amount in section `exchange' under `AML_THRESHOLD' uses the wrong currency!\n");
+ return GNUNET_SYSERR;
+ }
+ TEH_enable_tipping
+ = GNUNET_CONFIGURATION_get_value_yesno (
+ TEH_cfg,
+ "exchange",
+ "ENABLE_TIPPING");
+ if (GNUNET_SYSERR == TEH_enable_tipping)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Need YES or NO in section `exchange' under `ENABLE_TIPPING'\n");
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index 5ab0ea92..24e08772 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -65,6 +65,11 @@ extern int TEH_check_invariants_flag;
extern int TEH_allow_keys_timetravel;
/**
+ * Option set to #GNUNET_YES if tipping is enabled.
+ */
+extern int TEH_enable_tipping;
+
+/**
* Main directory with revocation data.
*/
extern char *TEH_revocation_directory;
@@ -98,6 +103,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
extern char *TEH_currency;
/**
+ * Name of the KYC-AML-trigger evaluation binary.
+ */
+extern char *TEH_kyc_aml_trigger;
+
+/**
* What is the largest amount we allow a peer to
* merge into a reserve before always triggering
* an AML check?
diff --git a/src/exchange/taler-exchange-httpd_aml-decision-get.c b/src/exchange/taler-exchange-httpd_aml-decision-get.c
index 6b36fe27..b4f337db 100644
--- a/src/exchange/taler-exchange-httpd_aml-decision-get.c
+++ b/src/exchange/taler-exchange-httpd_aml-decision-get.c
@@ -43,8 +43,6 @@
* @param[in,out] cls closure with a `json_t *` array to update
* @param h_payto account for which the attribute data is stored
* @param provider_section provider that must be checked
- * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
- * digits can be 0 if exact day, month or year are unknown
* @param collection_time when was the data collected
* @param expiration_time when does the data expire
* @param enc_attributes_size number of bytes in @a enc_attributes
@@ -55,7 +53,6 @@ kyc_attribute_cb (
void *cls,
const struct TALER_PaytoHashP *h_payto,
const char *provider_section,
- const char *birthdate,
struct GNUNET_TIME_Timestamp collection_time,
struct GNUNET_TIME_Timestamp expiration_time,
size_t enc_attributes_size,
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c
new file mode 100644
index 00000000..ef917a55
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -0,0 +1,239 @@
+/*
+ This file is part of TALER
+ Copyright (C) 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_common_kyc.c
+ * @brief shared logic for finishing a KYC process
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-exchange-httpd_common_kyc.h"
+#include "taler_attributes.h"
+#include "taler_exchangedb_plugin.h"
+
+struct TEH_KycAmlTrigger
+{
+
+ /**
+ * Our logging scope.
+ */
+ struct GNUNET_AsyncScopeId scope;
+
+ /**
+ * account the operation is about
+ */
+ struct TALER_PaytoHashP account_id;
+
+ /**
+ * until when is the KYC data valid
+ */
+ struct GNUNET_TIME_Absolute expiration;
+
+ /**
+ * legitimization process the KYC data is about
+ */
+ uint64_t process_row;
+
+ /**
+ * name of the configuration section of the logic that was run
+ */
+ char *provider_section;
+
+ /**
+ * set to user ID at the provider, or NULL if not supported or unknown
+ */
+ char *provider_user_id;
+
+ /**
+ * provider_legitimization_id set to legitimization process ID at the provider, or NULL if not supported or unknown
+ */
+ char *provider_legitimization_id;
+
+ /**
+ * function to call with the result
+ */
+ TEH_KycAmlTriggerCallback cb;
+
+ /**
+ * closure for @e cb
+ */
+ void *cb_cls;
+
+ /**
+ * user attributes returned by the provider
+ */
+ json_t *attributes;
+
+ /**
+ * response to return to the HTTP client
+ */
+ struct MHD_Response *response;
+
+ /**
+ * Handle to an external process that evaluates the
+ * need to run AML on the account.
+ */
+ struct TALER_JSON_ExternalConversion *kyc_aml;
+
+ /**
+ * HTTP status code of @e response
+ */
+ unsigned int http_status;
+
+};
+
+
+/**
+ * Type of a callback that receives a JSON @a result.
+ *
+ * @param cls closure of type `struct TEH_KycAmlTrigger *`
+ * @param status_type how did the process die
+ * @param code termination status code from the process
+ * @param result some JSON result, NULL if we failed to get an JSON output
+ */
+static void
+kyc_aml_finished (void *cls,
+ enum GNUNET_OS_ProcessStatusType status_type,
+ unsigned long code,
+ const json_t *result)
+{
+ struct TEH_KycAmlTrigger *kat = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ size_t eas;
+ void *ea;
+ const char *birthdate;
+ unsigned int birthday;
+ struct GNUNET_ShortHashCode kyc_prox;
+ struct GNUNET_AsyncScopeSave old_scope;
+
+ kat->kyc_aml = NULL;
+ GNUNET_async_scope_enter (&kat->scope,
+ &old_scope);
+ TALER_CRYPTO_attributes_to_kyc_prox (kat->attributes,
+ &kyc_prox);
+ birthdate = json_string_value (json_object_get (kat->attributes,
+ TALER_ATTRIBUTE_BIRTHDATE));
+ birthday = 0; (void) birthdate; // FIXME-Oec: calculate birthday here...
+ // Convert 'birthdate' to time after 1970, then compute days.
+ // Then compare against max age-restriction, and if before, set to 0.
+ TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
+ kat->attributes,
+ &ea,
+ &eas);
+ qs = TEH_plugin->insert_kyc_attributes (
+ TEH_plugin->cls,
+ kat->process_row,
+ &kat->account_id,
+ &kyc_prox,
+ kat->provider_section,
+ birthday,
+ GNUNET_TIME_timestamp_get (),
+ kat->provider_user_id,
+ kat->provider_legitimization_id,
+ kat->expiration,
+ eas,
+ ea,
+ 0 != code);
+ GNUNET_free (ea);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ {
+ GNUNET_break (0);
+ if (NULL != kat->response)
+ MHD_destroy_response (kat->response);
+ kat->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ kat->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
+ "do_insert_kyc_attributes");
+ }
+ /* Finally, return result to main handler */
+ kat->cb (kat->cb_cls,
+ kat->http_status,
+ kat->response);
+ kat->response = NULL;
+ TEH_kyc_finished_cancel (kat);
+ GNUNET_async_scope_restore (&old_scope);
+}
+
+
+struct TEH_KycAmlTrigger *
+TEH_kyc_finished (const struct GNUNET_AsyncScopeId *scope,
+ uint64_t process_row,
+ const struct TALER_PaytoHashP *account_id,
+ const char *provider_section,
+ const char *provider_user_id,
+ const char *provider_legitimization_id,
+ struct GNUNET_TIME_Absolute expiration,
+ const json_t *attributes,
+ unsigned int http_status,
+ struct MHD_Response *response,
+ TEH_KycAmlTriggerCallback cb,
+ void *cb_cls)
+{
+ struct TEH_KycAmlTrigger *kat;
+
+ kat = GNUNET_new (struct TEH_KycAmlTrigger);
+ kat->scope = *scope;
+ kat->process_row = process_row;
+ kat->account_id = *account_id;
+ kat->provider_section
+ = GNUNET_strdup (provider_section);
+ if (NULL != provider_user_id)
+ kat->provider_user_id
+ = GNUNET_strdup (provider_user_id);
+ if (NULL != provider_legitimization_id)
+ kat->provider_legitimization_id
+ = GNUNET_strdup (provider_legitimization_id);
+ kat->expiration = expiration;
+ kat->attributes = json_incref ((json_t*) attributes);
+ kat->http_status = http_status;
+ kat->response = response;
+ kat->cb = cb;
+ kat->cb_cls = cb_cls;
+ kat->kyc_aml
+ = TALER_JSON_external_conversion_start (
+ attributes,
+ &kyc_aml_finished,
+ kat,
+ TEH_kyc_aml_trigger,
+ TEH_kyc_aml_trigger,
+ NULL);
+ if (NULL == kat->kyc_aml)
+ {
+ GNUNET_break (0);
+ TEH_kyc_finished_cancel (kat);
+ return NULL;
+ }
+ return kat;
+}
+
+
+void
+TEH_kyc_finished_cancel (struct TEH_KycAmlTrigger *kat)
+{
+ if (NULL != kat->kyc_aml)
+ {
+ TALER_JSON_external_conversion_stop (kat->kyc_aml);
+ kat->kyc_aml = NULL;
+ }
+ GNUNET_free (kat->provider_section);
+ GNUNET_free (kat->provider_user_id);
+ GNUNET_free (kat->provider_legitimization_id);
+ json_decref (kat->attributes);
+ if (NULL != kat->response)
+ {
+ MHD_destroy_response (kat->response);
+ kat->response = NULL;
+ }
+ GNUNET_free (kat);
+}
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.h b/src/exchange/taler-exchange-httpd_common_kyc.h
new file mode 100644
index 00000000..57276604
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_common_kyc.h
@@ -0,0 +1,99 @@
+/*
+ This file is part of TALER
+ Copyright (C) 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_common_kyc.h
+ * @brief shared logic for finishing a KYC process
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_COMMON_KYC_H
+#define TALER_EXCHANGE_HTTPD_COMMON_KYC_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Function called after the KYC-AML trigger is done.
+ *
+ * @param cls closure
+ * @param http_status final HTTP status to return
+ * @param[in] response final HTTP ro return
+ */
+typedef void
+(*TEH_KycAmlTriggerCallback) (
+ void *cls,
+ unsigned int http_status,
+ struct MHD_Response *response);
+
+
+/**
+ * Handle for an asynchronous operation to finish
+ * a KYC process after running the AML trigger.
+ */
+struct TEH_KycAmlTrigger;
+
+// FIXME: also pass async log context and set it!
+/**
+ * We have finished a KYC process and obtained new
+ * @a attributes for a given @a account_id.
+ * Check with the KYC-AML trigger to see if we need
+ * to initiate an AML process, and store the attributes
+ * in the database. Then call @a cb.
+ *
+ * @param scope the HTTP request logging scope
+ * @param process_row legitimization process the webhook was about
+ * @param account_id account the webhook was about
+ * @param provider_section name of the configuration section of the logic that was run
+ * @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 expiration until when is the KYC check valid
+ * @param attributes user attributes returned by the provider
+ * @param http_status HTTP status code of @a response
+ * @param[in] response to return to the HTTP client
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel the operation
+ */
+struct TEH_KycAmlTrigger *
+TEH_kyc_finished (const struct GNUNET_AsyncScopeId *scope,
+ uint64_t process_row,
+ const struct TALER_PaytoHashP *account_id,
+ const char *provider_section,
+ const char *provider_user_id,
+ const char *provider_legitimization_id,
+ struct GNUNET_TIME_Absolute expiration,
+ const json_t *attributes,
+ unsigned int http_status,
+ struct MHD_Response *response,
+ TEH_KycAmlTriggerCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel KYC finish operation.
+ *
+ * @param[in] kat operation to abort
+ */
+void
+TEH_kyc_finished_cancel (struct TEH_KycAmlTrigger *kat);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index fa87a3b8..b39093ec 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -1857,6 +1857,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
TEH_currency),
GNUNET_JSON_pack_string ("asset_type",
asset_type),
+ GNUNET_JSON_pack_bool ("tipping_allowed",
+ GNUNET_YES == TEH_enable_tipping),
GNUNET_JSON_pack_data_auto ("master_public_key",
&TEH_master_public_key),
GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c
index 9668ee54..b3175bd2 100644
--- a/src/exchange/taler-exchange-httpd_kyc-proof.c
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2021-2022 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
@@ -23,11 +23,11 @@
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
#include <microhttpd.h>
-#include <pthread.h>
#include "taler_attributes.h"
#include "taler_json_lib.h"
#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_common_kyc.h"
#include "taler-exchange-httpd_kyc-proof.h"
#include "taler-exchange-httpd_responses.h"
@@ -69,6 +69,11 @@ struct KycProofContext
struct TALER_KYCLOGIC_ProofHandle *ph;
/**
+ * KYC AML trigger operation.
+ */
+ struct TEH_KycAmlTrigger *kat;
+
+ /**
* Process information about the user for the plugin from the database, can
* be NULL.
*/
@@ -160,6 +165,28 @@ TEH_kyc_proof_cleanup (void)
/**
+ * Function called after the KYC-AML trigger is done.
+ *
+ * @param cls closure
+ * @param http_status final HTTP status to return
+ * @param[in] response final HTTP ro return
+ */
+static void
+proof_finish (
+ void *cls,
+ unsigned int http_status,
+ struct MHD_Response *response)
+{
+ struct KycProofContext *kpc = cls;
+
+ kpc->kat = NULL;
+ kpc->response_code = http_status;
+ kpc->response = response;
+ kpc_resume (kpc);
+}
+
+
+/**
* Function called with the result of a proof check operation.
*
* Note that the "decref" for the @a response
@@ -192,74 +219,40 @@ proof_cb (
kpc->ph = NULL;
GNUNET_async_scope_enter (&rc->async_scope_id,
&old_scope);
-
if (TALER_KYCLOGIC_STATUS_SUCCESS == status)
{
- enum GNUNET_DB_QueryStatus qs;
- size_t eas;
- void *ea;
- const char *birthdate;
- struct GNUNET_ShortHashCode kyc_prox;
-
- TALER_CRYPTO_attributes_to_kyc_prox (attributes,
- &kyc_prox);
- birthdate = json_string_value (json_object_get (attributes,
- TALER_ATTRIBUTE_BIRTHDATE));
- TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
- attributes,
- &ea,
- &eas);
- qs = TEH_plugin->insert_kyc_attributes (
- TEH_plugin->cls,
- &kpc->h_payto,
- &kyc_prox,
- kpc->provider_section,
- birthdate,
- GNUNET_TIME_timestamp_get (),
- GNUNET_TIME_absolute_to_timestamp (expiration),
- eas,
- ea);
- GNUNET_free (ea);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- if (NULL != response)
- MHD_destroy_response (response);
- kpc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- kpc->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
- "insert_kyc_attributes");
- GNUNET_async_scope_restore (&old_scope);
- return;
- }
- qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
- kpc->process_row,
- kpc->provider_section,
- &kpc->h_payto,
- provider_user_id,
- provider_legitimization_id,
- expiration);
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+ kpc->kat = TEH_kyc_finished (&rc->async_scope_id,
+ kpc->process_row,
+ &kpc->h_payto,
+ kpc->provider_section,
+ provider_user_id,
+ provider_legitimization_id,
+ expiration,
+ attributes,
+ http_status,
+ response,
+ &proof_finish,
+ kpc);
+ if (NULL == kpc->kat)
{
- GNUNET_break (0);
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
if (NULL != response)
MHD_destroy_response (response);
- kpc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- kpc->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
- "set_kyc_ok");
- GNUNET_async_scope_restore (&old_scope);
- return;
+ response = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
+ "[exchange] AML_KYC_TRIGGER");
}
}
- else
+ if (NULL == kpc->kat)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC process #%llu failed with status %d\n",
(unsigned long long) kpc->process_row,
status);
+ proof_finish (kpc,
+ http_status,
+ response);
}
- kpc->response_code = http_status;
- kpc->response = response;
- kpc_resume (kpc);
GNUNET_async_scope_restore (&old_scope);
}
@@ -279,6 +272,11 @@ clean_kpc (struct TEH_RequestContext *rc)
kpc->logic->proof_cancel (kpc->ph);
kpc->ph = NULL;
}
+ if (NULL != kpc->kat)
+ {
+ TEH_kyc_finished_cancel (kpc->kat);
+ kpc->kat = NULL;
+ }
if (NULL != kpc->response)
{
MHD_destroy_response (kpc->response);
diff --git a/src/exchange/taler-exchange-httpd_kyc-webhook.c b/src/exchange/taler-exchange-httpd_kyc-webhook.c
index f8fe711d..415e5de9 100644
--- a/src/exchange/taler-exchange-httpd_kyc-webhook.c
+++ b/src/exchange/taler-exchange-httpd_kyc-webhook.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022-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
@@ -28,6 +28,7 @@
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler_kyclogic_lib.h"
+#include "taler-exchange-httpd_common_kyc.h"
#include "taler-exchange-httpd_kyc-webhook.h"
#include "taler-exchange-httpd_responses.h"
@@ -54,6 +55,11 @@ struct KycWebhookContext
struct TEH_RequestContext *rc;
/**
+ * Handle for the KYC-AML trigger interaction.
+ */
+ struct TEH_KycAmlTrigger *kat;
+
+ /**
* Plugin responsible for the webhook.
*/
struct TALER_KYCLOGIC_Plugin *plugin;
@@ -141,6 +147,28 @@ TEH_kyc_webhook_cleanup (void)
/**
+ * Function called after the KYC-AML trigger is done.
+ *
+ * @param cls closure with a `struct KycWebhookContext *`
+ * @param http_status final HTTP status to return
+ * @param[in] response final HTTP ro return
+ */
+static void
+kyc_aml_webhook_finished (
+ void *cls,
+ unsigned int http_status,
+ struct MHD_Response *response)
+{
+ struct KycWebhookContext *kwh = cls;
+
+ kwh->kat = NULL;
+ kwh->response = response;
+ kwh->response_code = http_status;
+ kwh_resume (kwh);
+}
+
+
+/**
* Function called with the result of a KYC webhook operation.
*
* Note that the "decref" for the @a response
@@ -178,58 +206,27 @@ webhook_finished_cb (
switch (status)
{
case TALER_KYCLOGIC_STATUS_SUCCESS:
- /* _successfully_ resumed case */
+ kwh->kat = TEH_kyc_finished (
+ &kwh->rc->async_scope_id,
+ process_row,
+ account_id,
+ provider_section,
+ provider_user_id,
+ provider_legitimization_id,
+ expiration,
+ attributes,
+ http_status,
+ response,
+ &kyc_aml_webhook_finished,
+ kwh);
+ if (NULL == kwh->kat)
{
- enum GNUNET_DB_QueryStatus qs;
- size_t eas;
- void *ea;
- const char *birthdate;
- struct GNUNET_ShortHashCode kyc_prox;
-
- TALER_CRYPTO_attributes_to_kyc_prox (attributes,
- &kyc_prox);
- birthdate = json_string_value (json_object_get (attributes,
- TALER_ATTRIBUTE_BIRTHDATE));
- TALER_CRYPTO_kyc_attributes_encrypt (&TEH_attribute_key,
- attributes,
- &ea,
- &eas);
- qs = TEH_plugin->insert_kyc_attributes (
- TEH_plugin->cls,
- account_id,
- &kyc_prox,
- provider_section,
- birthdate,
- GNUNET_TIME_timestamp_get (),
- GNUNET_TIME_absolute_to_timestamp (expiration),
- eas,
- ea);
- GNUNET_free (ea);
- if (qs < 0)
- {
- GNUNET_break (0);
- kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
- "insert_kyc_attributes");
- kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- kwh_resume (kwh);
- return;
- }
- qs = TEH_plugin->update_kyc_process_by_row (TEH_plugin->cls,
- process_row,
- provider_section,
- account_id,
- provider_user_id,
- provider_legitimization_id,
- expiration);
- if (qs < 0)
- {
- GNUNET_break (0);
- kwh->response = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
- "set_kyc_ok");
- kwh->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
- kwh_resume (kwh);
- return;
- }
+ http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ if (NULL != response)
+ MHD_destroy_response (response);
+ response = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
+ "[exchange] AML_KYC_TRIGGER");
}
break;
default:
@@ -241,9 +238,10 @@ webhook_finished_cb (
status);
break;
}
- kwh->response = response;
- kwh->response_code = http_status;
- kwh_resume (kwh);
+ if (NULL == kwh->kat)
+ kyc_aml_webhook_finished (kwh,
+ http_status,
+ response);
}
@@ -262,6 +260,11 @@ clean_kwh (struct TEH_RequestContext *rc)
kwh->plugin->webhook_cancel (kwh->wh);
kwh->wh = NULL;
}
+ if (NULL != kwh->kat)
+ {
+ TEH_kyc_finished_cancel (kwh->kat);
+ kwh->kat = NULL;
+ }
if (NULL != kwh->response)
{
MHD_destroy_response (kwh->response);
diff --git a/src/exchange/taler-exchange-httpd_reserves_attest.c b/src/exchange/taler-exchange-httpd_reserves_attest.c
index 297d8cee..d0f3614e 100644
--- a/src/exchange/taler-exchange-httpd_reserves_attest.c
+++ b/src/exchange/taler-exchange-httpd_reserves_attest.c
@@ -158,8 +158,6 @@ reply_reserve_attest_success (struct MHD_Connection *connection,
* @param cls our `struct ReserveAttestContext *`
* @param h_payto account for which the attribute data is stored
* @param provider_section provider that must be checked
- * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
- * digits can be 0 if exact day, month or year are unknown
* @param collection_time when was the data collected
* @param expiration_time when does the data expire
* @param enc_attributes_size number of bytes in @a enc_attributes
@@ -169,7 +167,6 @@ static void
kyc_process_cb (void *cls,
const struct TALER_PaytoHashP *h_payto,
const char *provider_section,
- const char *birthdate,
struct GNUNET_TIME_Timestamp collection_time,
struct GNUNET_TIME_Timestamp expiration_time,
size_t enc_attributes_size,
diff --git a/src/exchange/taler-exchange-httpd_reserves_get_attest.c b/src/exchange/taler-exchange-httpd_reserves_get_attest.c
index b53a8641..ae983682 100644
--- a/src/exchange/taler-exchange-httpd_reserves_get_attest.c
+++ b/src/exchange/taler-exchange-httpd_reserves_get_attest.c
@@ -64,8 +64,6 @@ struct ReserveAttestContext
* @param cls our `struct ReserveAttestContext *`
* @param h_payto account for which the attribute data is stored
* @param provider_section provider that must be checked
- * @param birthdate birthdate of user, in format YYYY-MM-DD; can be NULL;
- * digits can be 0 if exact day, month or year are unknown
* @param collection_time when was the data collected
* @param expiration_time when does the data expire
* @param enc_attributes_size number of bytes in @a enc_attributes
@@ -75,7 +73,6 @@ static void
kyc_process_cb (void *cls,
const struct TALER_PaytoHashP *h_payto,
const char *provider_section,
- const char *birthdate,
struct GNUNET_TIME_Timestamp collection_time,
struct GNUNET_TIME_Timestamp expiration_time,
size_t enc_attributes_size,
diff --git a/src/exchange/taler-exchange-kyc-aml-pep-trigger.sh b/src/exchange/taler-exchange-kyc-aml-pep-trigger.sh
new file mode 100755
index 00000000..9baa32ba
--- /dev/null
+++ b/src/exchange/taler-exchange-kyc-aml-pep-trigger.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+# This file is in the public domain.
+# This is an example of how to trigger AML if the
+# KYC attributes include '{"pep":true}'
+#
+# To be used as a script for the KYC_AML_TRIGGER.
+test "false" = $(jq .pep -)
diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf
index 0af23b9d..80cf6230 100644
--- a/src/exchange/test_taler_exchange_httpd.conf
+++ b/src/exchange/test_taler_exchange_httpd.conf
@@ -7,13 +7,14 @@ TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
-AML_THRESHOLD = EUR:1000000
[auditor]
TINY_AMOUNT = EUR:0.01
[exchange]
+AML_THRESHOLD = EUR:1000000
+
# Directory with our terms of service.
TERMS_DIR = ../../contrib/tos