summaryrefslogtreecommitdiff
path: root/src/exchange
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-08-14 18:04:09 +0200
committerChristian Grothoff <christian@grothoff.org>2022-08-14 18:04:09 +0200
commit74ba46db39d3a906e819cd0ed48f1d46dffe9e38 (patch)
tree53f050bacd2e634dc5e746a257b10be9294afa71 /src/exchange
parent913eacf506860a73043be09425d1c143b786e871 (diff)
downloadexchange-74ba46db39d3a906e819cd0ed48f1d46dffe9e38.tar.gz
exchange-74ba46db39d3a906e819cd0ed48f1d46dffe9e38.tar.bz2
exchange-74ba46db39d3a906e819cd0ed48f1d46dffe9e38.zip
-work on new KYC logic: tests pass again
Diffstat (limited to 'src/exchange')
-rw-r--r--src/exchange/taler-exchange-httpd_batch-withdraw.c7
-rw-r--r--src/exchange/taler-exchange-httpd_deposits_get.c2
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-wallet.c2
-rw-r--r--src/exchange/taler-exchange-httpd_purses_merge.c96
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_get.c2
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_purse.c97
-rw-r--r--src/exchange/taler-exchange-httpd_reserves_status.c21
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c12
-rw-r--r--src/exchange/taler-exchange-httpd_responses.h13
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c9
10 files changed, 194 insertions, 67 deletions
diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c b/src/exchange/taler-exchange-httpd_batch-withdraw.c
index 9e24ff4c3..635a968d3 100644
--- a/src/exchange/taler-exchange-httpd_batch-withdraw.c
+++ b/src/exchange/taler-exchange-httpd_batch-withdraw.c
@@ -327,11 +327,8 @@ generate_reply_success (const struct TEH_RequestContext *rc,
if (! wc->kyc.ok)
{
/* KYC required */
- return TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- GNUNET_JSON_pack_uint64 ("payment_target_uuid",
- wc->kyc.payment_target_uuid));
+ return TEH_RESPONSE_reply_kyc_required (rc->connection,
+ &wc->kyc);
}
sigs = json_array ();
diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c
index eec815690..682cb6ecd 100644
--- a/src/exchange/taler-exchange-httpd_deposits_get.c
+++ b/src/exchange/taler-exchange-httpd_deposits_get.c
@@ -247,7 +247,7 @@ handle_track_transaction_request (
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
"wire fees exceed aggregate in database");
- if (GNUNET_YES == ctx->pending)
+ if (ctx->pending)
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.c b/src/exchange/taler-exchange-httpd_kyc-wallet.c
index a043de6ff..9a1133c7f 100644
--- a/src/exchange/taler-exchange-httpd_kyc-wallet.c
+++ b/src/exchange/taler-exchange-httpd_kyc-wallet.c
@@ -227,7 +227,7 @@ TEH_handler_kyc_wallet (
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
- GNUNET_JSON_pack_uint64 ("payment_target_uuid",
+ GNUNET_JSON_pack_uint64 ("legitimization_uuid",
krc.legi_row));
}
diff --git a/src/exchange/taler-exchange-httpd_purses_merge.c b/src/exchange/taler-exchange-httpd_purses_merge.c
index 25d91e1be..c1db6cf39 100644
--- a/src/exchange/taler-exchange-httpd_purses_merge.c
+++ b/src/exchange/taler-exchange-httpd_purses_merge.c
@@ -28,6 +28,7 @@
#include <pthread.h>
#include "taler_dbevents.h"
#include "taler_json_lib.h"
+#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_purses_merge.h"
#include "taler-exchange-httpd_responses.h"
@@ -103,11 +104,21 @@ struct PurseMergeContext
/**
* URI of the account the purse is to be merged into.
- * Must be of the form 'payto://taler/$EXCHANGE_URL/RESERVE_PUB'.
+ * Must be of the form 'payto://taler-reserve/$EXCHANGE_URL/RESERVE_PUB'.
*/
const char *payto_uri;
/**
+ * Hash of the @e payto_uri.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * KYC status of the operation.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ /**
* Base URL of the exchange provider hosting the reserve.
*/
char *provider_url;
@@ -202,6 +213,46 @@ reply_merge_success (struct MHD_Connection *connection,
/**
+ * Function called to iterate over KYC-relevant
+ * transaction amounts for a particular time range.
+ * Called within a database transaction, so must
+ * not start a new one.
+ *
+ * @param cls a `struct PurseMergeContext`
+ * @param limit maximum time-range for which events
+ * should be fetched (timestamp in the past)
+ * @param cb function to call on each event found,
+ * events must be returned in reverse chronological
+ * order
+ * @param cb_cls closure for @a cb
+ */
+static void
+amount_iterator (void *cls,
+ struct GNUNET_TIME_Absolute limit,
+ TALER_EXCHANGEDB_KycAmountCallback cb,
+ void *cb_cls)
+{
+ struct PurseMergeContext *pcc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ cb (cb_cls,
+ &pcc->target_amount,
+ GNUNET_TIME_absolute_get ());
+ qs = TEH_plugin->select_merge_amounts_for_kyc_check (
+ TEH_plugin->cls,
+ &pcc->h_payto,
+ limit,
+ cb,
+ cb_cls);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got %d additional transactions for this merge and limit %llu\n",
+ qs,
+ (unsigned long long) limit.abs_value_us);
+ GNUNET_break (qs >= 0);
+}
+
+
+/**
* Execute database transaction for /purses/$PID/merge. 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
@@ -224,9 +275,26 @@ merge_transaction (void *cls,
bool in_conflict = true;
bool no_balance = true;
bool no_partner = true;
- bool no_kyc = true;
bool no_reserve = true;
+ const char *required;
+ required = TALER_KYCLOGIC_kyc_test_required (
+ TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE,
+ &pcc->h_payto,
+ TEH_plugin->select_satisfied_kyc_processes,
+ TEH_plugin->cls,
+ &amount_iterator,
+ pcc);
+ if (NULL != required)
+ {
+ pcc->kyc.ok = false;
+ return TEH_plugin->insert_kyc_requirement_for_account (
+ TEH_plugin->cls,
+ required,
+ &pcc->h_payto,
+ &pcc->kyc.payment_target_uuid);
+ }
+ pcc->kyc.ok = true;
qs = TEH_plugin->do_purse_merge (
TEH_plugin->cls,
pcc->purse_pub,
@@ -235,11 +303,9 @@ merge_transaction (void *cls,
&pcc->reserve_sig,
pcc->provider_url,
&pcc->reserve_pub,
- TEH_KYC_NONE != TEH_kyc_config.mode,
&no_partner,
&no_balance,
&no_reserve,
- &no_kyc,
&in_conflict);
if (qs < 0)
{
@@ -272,17 +338,6 @@ merge_transaction (void *cls,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
- if ( (no_kyc) &&
- (TEH_KYC_NONE != TEH_kyc_config.mode) )
- {
- *mhd_ret
- = TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- TALER_JSON_pack_ec (
- TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED));
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
if (no_balance)
{
*mhd_ret =
@@ -333,6 +388,7 @@ merge_transaction (void *cls,
GNUNET_free (partner_url);
return GNUNET_DB_STATUS_HARD_ERROR;
}
+
return qs;
}
@@ -434,7 +490,6 @@ TEH_handler_purses_merge (
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"payto_uri");
}
-
http = (0 == strncmp (pcc.payto_uri,
"payto://taler-reserve+http/",
strlen ("payto://taler-reserve+http/")));
@@ -477,6 +532,8 @@ TEH_handler_purses_merge (
}
slash++;
}
+ TALER_payto_hash (pcc.payto_uri,
+ &pcc.h_payto);
if (0 == strcmp (pcc.provider_url,
TEH_base_url))
{
@@ -615,6 +672,12 @@ TEH_handler_purses_merge (
}
}
+
+ GNUNET_free (pcc.provider_url);
+ if (! pcc.kyc.ok)
+ return TEH_RESPONSE_reply_kyc_required (connection,
+ &pcc.kyc);
+
{
struct TALER_PurseEventP rep = {
.header.size = htons (sizeof (rep)),
@@ -630,7 +693,6 @@ TEH_handler_purses_merge (
0);
}
- GNUNET_free (pcc.provider_url);
/* generate regular response */
return reply_merge_success (connection,
&pcc);
diff --git a/src/exchange/taler-exchange-httpd_reserves_get.c b/src/exchange/taler-exchange-httpd_reserves_get.c
index 27f8faecd..19fb7df8e 100644
--- a/src/exchange/taler-exchange-httpd_reserves_get.c
+++ b/src/exchange/taler-exchange-httpd_reserves_get.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2022 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
diff --git a/src/exchange/taler-exchange-httpd_reserves_purse.c b/src/exchange/taler-exchange-httpd_reserves_purse.c
index d377323e4..4730a5791 100644
--- a/src/exchange/taler-exchange-httpd_reserves_purse.c
+++ b/src/exchange/taler-exchange-httpd_reserves_purse.c
@@ -27,6 +27,7 @@
#include <microhttpd.h>
#include <pthread.h>
#include "taler_json_lib.h"
+#include "taler_kyclogic_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_reserves_purse.h"
#include "taler-exchange-httpd_responses.h"
@@ -101,6 +102,16 @@ struct ReservePurseContext
struct TEH_PurseDetails pd;
/**
+ * Hash of the @e payto_uri.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * KYC status of the operation.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ /**
* Minimum age for deposits into this purse.
*/
uint32_t min_age;
@@ -119,6 +130,46 @@ struct ReservePurseContext
/**
+ * Function called to iterate over KYC-relevant
+ * transaction amounts for a particular time range.
+ * Called within a database transaction, so must
+ * not start a new one.
+ *
+ * @param cls a `struct ReservePurseContext`
+ * @param limit maximum time-range for which events
+ * should be fetched (timestamp in the past)
+ * @param cb function to call on each event found,
+ * events must be returned in reverse chronological
+ * order
+ * @param cb_cls closure for @a cb
+ */
+static void
+amount_iterator (void *cls,
+ struct GNUNET_TIME_Absolute limit,
+ TALER_EXCHANGEDB_KycAmountCallback cb,
+ void *cb_cls)
+{
+ struct ReservePurseContext *rpc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ cb (cb_cls,
+ &rpc->deposit_total,
+ GNUNET_TIME_absolute_get ());
+ qs = TEH_plugin->select_merge_amounts_for_kyc_check (
+ TEH_plugin->cls,
+ &rpc->h_payto,
+ limit,
+ cb,
+ cb_cls);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Got %d additional transactions for this merge and limit %llu\n",
+ qs,
+ (unsigned long long) limit.abs_value_us);
+ GNUNET_break (qs >= 0);
+}
+
+
+/**
* Execute database transaction for /reserves/$PID/purse. 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
@@ -139,6 +190,26 @@ purse_transaction (void *cls,
struct ReservePurseContext *rpc = cls;
enum GNUNET_DB_QueryStatus qs;
+ const char *required;
+
+ required = TALER_KYCLOGIC_kyc_test_required (
+ TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE,
+ &rpc->h_payto,
+ TEH_plugin->select_satisfied_kyc_processes,
+ TEH_plugin->cls,
+ &amount_iterator,
+ rpc);
+ if (NULL != required)
+ {
+ rpc->kyc.ok = false;
+ return TEH_plugin->insert_kyc_requirement_for_account (
+ TEH_plugin->cls,
+ required,
+ &rpc->h_payto,
+ &rpc->kyc.payment_target_uuid);
+ }
+ rpc->kyc.ok = true;
+
{
bool in_conflict = true;
@@ -230,7 +301,6 @@ purse_transaction (void *cls,
bool in_conflict = true;
bool insufficient_funds = true;
bool no_reserve = true;
- bool no_kyc = true;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Creating purse with flags %d\n",
@@ -246,10 +316,8 @@ purse_transaction (void *cls,
? NULL
: &rpc->gf->fees.purse,
rpc->reserve_pub,
- TEH_KYC_NONE != TEH_kyc_config.mode,
&in_conflict,
&no_reserve,
- &no_kyc,
&insufficient_funds);
if (qs < 0)
{
@@ -322,17 +390,6 @@ purse_transaction (void *cls,
TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN));
return GNUNET_DB_STATUS_HARD_ERROR;
}
- if ( (no_kyc) &&
- (TEH_KYC_NONE != TEH_kyc_config.mode) )
- {
- *mhd_ret
- = TALER_MHD_REPLY_JSON_PACK (
- connection,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- TALER_JSON_pack_ec (
- TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED));
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
if (insufficient_funds)
{
*mhd_ret
@@ -472,6 +529,15 @@ TEH_handler_reserves_purse (
return MHD_YES; /* failure */
}
}
+ {
+ char *payto_uri;
+
+ payto_uri = TALER_reserve_make_payto (TEH_base_url,
+ reserve_pub);
+ TALER_payto_hash (payto_uri,
+ &rpc.h_payto);
+ GNUNET_free (payto_uri);
+ }
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (TEH_currency,
&rpc.deposit_total));
@@ -641,6 +707,9 @@ TEH_handler_reserves_purse (
}
}
+ if (! rpc.kyc.ok)
+ return TEH_RESPONSE_reply_kyc_required (connection,
+ &rpc.kyc);
/* generate regular response */
{
MHD_RESULT res;
diff --git a/src/exchange/taler-exchange-httpd_reserves_status.c b/src/exchange/taler-exchange-httpd_reserves_status.c
index ff8a65c23..4e7b4f47c 100644
--- a/src/exchange/taler-exchange-httpd_reserves_status.c
+++ b/src/exchange/taler-exchange-httpd_reserves_status.c
@@ -54,11 +54,6 @@ struct ReserveStatusContext
struct TALER_EXCHANGEDB_ReserveHistory *rh;
/**
- * Current KYC status.
- */
- struct TALER_EXCHANGEDB_KycStatus kyc;
-
- /**
* Sum of incoming transactions within the returned history.
* (currently not used).
*/
@@ -102,8 +97,6 @@ reply_reserve_status_success (struct MHD_Connection *connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rhc->balance),
- GNUNET_JSON_pack_bool ("kyc_passed",
- rhc->kyc.ok),
GNUNET_JSON_pack_array_steal ("history",
json_history));
}
@@ -133,20 +126,6 @@ reserve_status_transaction (void *cls,
struct ReserveStatusContext *rsc = cls;
enum GNUNET_DB_QueryStatus qs;
- qs = TEH_plugin->inselect_wallet_kyc_status (TEH_plugin->cls,
- rsc->reserve_pub,
- &rsc->kyc);
- 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,
- "inselect_wallet_status");
- return qs;
- }
qs = TEH_plugin->get_reserve_status (TEH_plugin->cls,
rsc->reserve_pub,
&rsc->balance_in,
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index 2642f433a..0320a07b3 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -977,4 +977,16 @@ TEH_RESPONSE_reply_purse_created (
}
+MHD_RESULT
+TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_KycStatus *kyc)
+{
+ return TALER_MHD_REPLY_JSON_PACK (
+ connection,
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
+ GNUNET_JSON_pack_uint64 ("legitimization_uuid",
+ kyc->payment_target_uuid));
+}
+
+
/* end of taler-exchange-httpd_responses.c */
diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h
index 6cd672414..9243960d8 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -75,6 +75,19 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (
/**
+ * Send information that a KYC check must be
+ * satisfied to proceed to client.
+ *
+ * @param connection connection to the client
+ * @param pcc details about the request that succeeded
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection,
+ const struct TALER_EXCHANGEDB_KycStatus *kyc);
+
+
+/**
* Send assertion that the given denomination key hash
* is not usable (typically expired) at this time.
*
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index 255f7d948..920147d4a 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -490,13 +490,8 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
GNUNET_JSON_parse_free (spec);
if (! wc.kyc.ok)
- {
- return TALER_MHD_REPLY_JSON_PACK (
- rc->connection,
- MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
- GNUNET_JSON_pack_uint64 ("payment_target_uuid",
- wc.kyc.payment_target_uuid));
- }
+ return TEH_RESPONSE_reply_kyc_required (rc->connection,
+ &wc.kyc);
{
MHD_RESULT ret;